pxt-arcade 1.12.16 → 1.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/built/target.js CHANGED
@@ -1182,10 +1182,10 @@ var pxtTargetBundle = {
1182
1182
  }
1183
1183
  ],
1184
1184
  "versions": {
1185
- "branch": "v1.12.16",
1186
- "tag": "v1.12.16",
1187
- "commits": "https://github.com/microsoft/pxt-arcade/commits/a8fdd30c00f5c318c3693aff3079dcffe3af2cdb",
1188
- "target": "1.12.16",
1185
+ "branch": "v1.13.1",
1186
+ "tag": "v1.13.1",
1187
+ "commits": "https://github.com/microsoft/pxt-arcade/commits/4aa2e41f66166d2424de8a5f67696a2973708083",
1188
+ "target": "1.13.1",
1189
1189
  "pxt": "8.5.22"
1190
1190
  },
1191
1191
  "blocksprj": {
@@ -1236,7 +1236,7 @@ var pxtTargetBundle = {
1236
1236
  "animation": {
1237
1237
  "README.md": "# Animations\n\nA small animation library.",
1238
1238
  "legacy.ts": "/*\n Animation library for sprites\n*/\nnamespace animation {\n //Handles all the updates\n let animations: Animation[];\n\n let animationStateStack: {\n state: Animation[],\n scene: scene.Scene\n }[];\n\n game.addScenePushHandler(oldScene => {\n if (animations) {\n if (!animationStateStack) animationStateStack = [];\n animationStateStack.push({\n state: animations,\n scene: oldScene\n });\n animations = undefined;\n }\n });\n\n game.addScenePopHandler(() => {\n const scene = game.currentScene();\n animations = undefined;\n if (animationStateStack && animationStateStack.length) {\n const nextState = animationStateStack.pop();\n if (nextState.scene == scene) {\n animations = nextState.state;\n } else {\n animationStateStack.push(nextState);\n }\n }\n });\n\n export class Animation {\n\n sprites: Sprite[];\n frames: Image[];\n index: number;\n interval: number;\n action: number;\n lastTime: number;\n\n constructor(action: number, interval: number) {\n this.interval = interval;\n this.index = -1;\n this.action = action;\n this.frames = [];\n this.sprites = [];\n this.lastTime = control.millis();\n\n this._init();\n }\n\n _init() {\n if (!animations) {\n animations = [];\n game.eventContext().registerFrameHandler(scene.ANIMATION_UPDATE_PRIORITY, () => {\n animations.forEach(anim => anim.update());\n });\n }\n animations.push(this);\n }\n\n update() {\n let currentTime = control.millis();\n let dt = currentTime - this.lastTime;\n if (dt >= this.interval && this.frames.length) {\n this.index = (this.index + 1) % this.frames.length;\n this.lastTime = currentTime;\n }\n\n this.sprites = this.sprites.filter(sprite => !(sprite.flags & sprites.Flag.Destroyed));\n\n this.sprites.forEach(sprite => {\n if (sprite._action === this.action) {\n let newImage = this.getImage();\n //Update only if the image has changed\n if (sprite.image !== newImage) {\n sprite.setImage(newImage);\n }\n }\n });\n }\n\n getImage() {\n return this.frames[this.index];\n }\n\n getAction() {\n return this.action;\n }\n\n getInterval() {\n return this.interval;\n }\n\n setInterval(interval: number) {\n this.interval = interval;\n }\n\n /**\n * Add an image frame to an animation\n */\n //% blockId=addAnimationFrame\n //% block=\"add frame $frame=screen_image_picker to $this=variables_get(anim)\"\n //% group=\"Advanced\"\n //% weight=40\n //% help=animation/add-animation-frame\n addAnimationFrame(frame: Image) {\n this.frames[++this.index] = frame;\n }\n\n registerSprite(sprite: Sprite) {\n if (this.sprites.indexOf(sprite) === -1) {\n this.sprites.push(sprite);\n }\n }\n\n }\n\n //% shim=ENUM_GET\n //% blockId=action_enum_shim\n //% block=\"%arg\"\n //% group=\"Advanced\"\n //% enumName=\"ActionKind\"\n //% enumMemberName=\"action\"\n //% enumPromptHint=\"e.g. Walking, Idle, Jumping, ...\"\n //% enumInitialMembers=\"Walking, Idle, Jumping\"\n //% weight=10\n export function _actionEnumShim(arg: number) {\n // This function should do nothing, but must take in a single\n // argument of type number and return a number value.\n return arg;\n }\n\n /**\n * Create an animation\n */\n //% blockId=createAnimation\n //% block=\"create animation of $action=action_enum_shim with interval $interval ms\"\n //% group=\"Advanced\"\n //% interval.defl=1000\n //% blockSetVariable=\"anim\"\n //% weight=50\n //% help=animation/create-animation\n export function createAnimation(action: number, interval: number) {\n return new Animation(action, interval);\n }\n\n /**\n * Attach an animation to a sprite\n */\n //% blockId=attachAnimation\n //% block=\"attach animation $set=variables_get(anim) to sprite $sprite=variables_get(mySprite)\"\n //% group=\"Advanced\"\n //% weight=30\n //% help=animation/attach-animation\n export function attachAnimation(sprite: Sprite, set: Animation) {\n set.registerSprite(sprite);\n }\n\n /**\n * Set an animation action to a sprite\n */\n //% blockId=setAction\n //% block=\"activate animation $action=action_enum_shim on $sprite=variables_get(mySprite)\"\n //% group=\"Advanced\"\n //% weight=20\n //% help=animation/set-action\n export function setAction(sprite: Sprite, action: number) {\n sprite._action = action;\n }\n\n}",
1239
- "pxt.json": "{\n \"name\": \"animation\",\n \"description\": \"Advanced state based animations for sprites\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"legacy.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 80,\n \"icon\": \"/static/libs/animation.png\"\n}\n",
1239
+ "pxt.json": "{\n \"name\": \"animation\",\n \"description\": \"Advanced state based animations for sprites\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"legacy.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 80,\n \"icon\": \"/static/libs/animation.png\"\n}\n",
1240
1240
  "targetoverrides.ts": "// TODO any platform specific overrides",
1241
1241
  "test.ts": "let mySprite: Sprite = sprites.create(img`\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n `, SpriteKind.Player);\nanimation.runImageAnimation(\n mySprite,\n [img`\n 1 . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n `,\n img`\n 2 . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n `],\n 500\n)\nanimation.runMovementAnimation(\n mySprite,\n animation.animationPresets(animation.flyToCenter),\n 500\n)\nanimation.runImageAnimation(\n mySprite,\n [img`\n 1 . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n `,\n img`\n 2 . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . . \n . . . . . . . . . . . . . . . .\n . . . . . . . . . . . . . . . .\n `],\n 500,\n true\n)\nanimation.runMovementAnimation(\n mySprite,\n animation.animationPresets(animation.flyToCenter),\n 500\n)"
1242
1242
  },
@@ -1249,7 +1249,7 @@ var pxtTargetBundle = {
1249
1249
  "gesture.ts": "namespace input {\n /**\n * Registers a custom gesture recognizer\n * @param id \n * @param update true if gesture detected\n * @param handler \n */\n export function onCustomGesture(\n id: number, \n update: () => boolean, \n handler: () => void) {\n if (!update || !handler) return;\n\n input.acceleration(Dimension.X); // turn on accelerometer\n const evid = DAL.ACCELEROMETER_EVT_2G + 1 + (id | 0);\n control.onEvent(DAL.DEVICE_ID_GESTURE, evid, handler);\n let sigma = 0;\n control.onIdle(function() {\n if (sigma > 0) {\n sigma--;\n } else if(update()) {\n sigma = 6;\n control.raiseEvent(DAL.DEVICE_ID_GESTURE, evid);\n }\n })\n }\n}",
1250
1250
  "ns.ts": "\n//% color=\"#B4009E\" weight=98 icon=\"\\uf192\"\nnamespace input {\n}",
1251
1251
  "part.svg": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg\n xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n xmlns:cc=\"http://creativecommons.org/ns#\"\n xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n xmlns:svg=\"http://www.w3.org/2000/svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"\n width=\"92.834999\"\n height=\"48.351559\"\n y=\"0\"\n x=\"0\"\n viewBox=\"0 0 92.834999 48.351559\"\n id=\"svg4493\"\n version=\"1.1\"\n sodipodi:docname=\"part.svg\"\n inkscape:version=\"0.92.1 r15371\">\n <metadata\n id=\"metadata4514\">\n <rdf:RDF>\n <cc:Work\n rdf:about=\"\">\n <dc:format>image/svg+xml</dc:format>\n <dc:type\n rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n <dc:title />\n </cc:Work>\n </rdf:RDF>\n </metadata>\n <defs\n id=\"defs4512\" />\n <sodipodi:namedview\n pagecolor=\"#ffffff\"\n bordercolor=\"#666666\"\n borderopacity=\"1\"\n objecttolerance=\"10\"\n gridtolerance=\"10\"\n guidetolerance=\"10\"\n inkscape:pageopacity=\"0\"\n inkscape:pageshadow=\"2\"\n inkscape:window-width=\"1600\"\n inkscape:window-height=\"837\"\n id=\"namedview4510\"\n showgrid=\"false\"\n inkscape:zoom=\"8.2495794\"\n inkscape:cx=\"42.339269\"\n inkscape:cy=\"33.871495\"\n inkscape:window-x=\"-8\"\n inkscape:window-y=\"-8\"\n inkscape:window-maximized=\"1\"\n inkscape:current-layer=\"svg4493\"\n fit-margin-top=\"0\"\n fit-margin-left=\"0\"\n fit-margin-right=\"0\"\n fit-margin-bottom=\"0\"\n units=\"px\"\n inkscape:measure-start=\"-5.21239,56.8514\"\n inkscape:measure-end=\"23.6376,42.184\" />\n <rect\n rx=\"1.1604376\"\n y=\"0.048351564\"\n height=\"48.254856\"\n width=\"92.738297\"\n id=\"rect5038\"\n x=\"0.048351564\"\n style=\"fill:#5a86c2;stroke:#8e8e8e;stroke-width:0.09670313\" />\n <text\n id=\"text5094\"\n y=\"40.50362\"\n x=\"4.5252295\"\n style=\"font-weight:400;font-size:13.53218174px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.37589398\"\n font-weight=\"400\"\n font-size=\"14.4\"\n letter-spacing=\"0\"\n word-spacing=\"0\"\n transform=\"scale(0.99296988,1.0070799)\">\n <tspan\n y=\"40.50362\"\n x=\"4.5252295\"\n id=\"tspan5092\"\n style=\"font-size:10.02383709px;stroke-width:0.37589398\">ACCELEROMETER</tspan>\n </text>\n <rect\n rx=\"0.78499681\"\n y=\"32.338985\"\n x=\"77.394577\"\n height=\"10.968015\"\n width=\"11.303953\"\n id=\"rect5096\"\n style=\"stroke:#000000;stroke-width:0.3893353\" />\n <ellipse\n style=\"fill:#ffffff;stroke:#000000;stroke-width:0.32272443\"\n cy=\"-5.9231954\"\n cx=\"-9.2452202\"\n id=\"ACCELEROMETER_INT\"\n transform=\"scale(-1)\"\n rx=\"3.23646\"\n ry=\"3.218055\"\n inkscape:label=\"#path5042-7-6\" />\n <text\n transform=\"matrix(0,1.0070833,-0.99296652,0,0,0)\"\n id=\"text5100-8-5\"\n y=\"-7.1094813\"\n x=\"10.925499\"\n style=\"font-weight:400;font-size:6.13176918px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.32272473\"\n font-weight=\"400\"\n font-size=\"1.9\"\n letter-spacing=\"0\"\n word-spacing=\"0\">\n <tspan\n y=\"-7.1094813\"\n x=\"10.925499\"\n id=\"tspan5098-2-4\"\n style=\"stroke-width:0.32272473\">INT</tspan>\n </text>\n <ellipse\n style=\"fill:#ffffff;stroke:#000000;stroke-width:0.32272443\"\n cy=\"-5.9231954\"\n cx=\"-39.334583\"\n id=\"SDA\"\n transform=\"scale(-1)\"\n rx=\"3.23646\"\n ry=\"3.218055\"\n inkscape:label=\"#path5042-7-3\" />\n <text\n transform=\"matrix(0,1.0070833,-0.99296652,0,0,0)\"\n id=\"text5100-8-5-4\"\n y=\"-37.301361\"\n x=\"11.108133\"\n style=\"font-weight:400;font-size:6.13176918px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.32272473\"\n font-weight=\"400\"\n font-size=\"1.9\"\n letter-spacing=\"0\"\n word-spacing=\"0\">\n <tspan\n id=\"tspan5156\"\n y=\"-37.301361\"\n x=\"11.108133\"\n style=\"stroke-width:0.32272473\">SDA</tspan>\n </text>\n <ellipse\n style=\"fill:#ffffff;stroke:#000000;stroke-width:0.32272443\"\n cy=\"-5.9231954\"\n cx=\"-70.055618\"\n id=\"VCC\"\n transform=\"scale(-1)\"\n rx=\"3.23646\"\n ry=\"3.218055\"\n inkscape:label=\"#path5042-7-1\" />\n <text\n transform=\"matrix(0,1.0070833,-0.99296652,0,0,0)\"\n id=\"text5100-8-5-4-9\"\n y=\"-68.672005\"\n x=\"11.428495\"\n style=\"font-weight:400;font-size:6.13176918px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.32272473\"\n font-weight=\"400\"\n font-size=\"1.9\"\n letter-spacing=\"0\"\n word-spacing=\"0\">\n <tspan\n id=\"tspan5156-5\"\n y=\"-68.672005\"\n x=\"11.428495\"\n style=\"stroke-width:0.32272473\">VCC</tspan>\n </text>\n <ellipse\n style=\"fill:#ffffff;stroke:#000000;stroke-width:0.32272443\"\n cy=\"-5.9231954\"\n cx=\"-85.100304\"\n id=\"GND\"\n transform=\"scale(-1)\"\n rx=\"3.23646\"\n ry=\"3.218055\"\n inkscape:label=\"#path5042-7-0\" />\n <text\n transform=\"matrix(0,1.0070833,-0.99296652,0,0,0)\"\n id=\"text5100-8-5-4-9-3\"\n y=\"-83.929306\"\n x=\"11.242865\"\n style=\"font-weight:400;font-size:6.13176918px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.32272473\"\n font-weight=\"400\"\n font-size=\"1.9\"\n letter-spacing=\"0\"\n word-spacing=\"0\">\n <tspan\n id=\"tspan5156-5-7\"\n y=\"-83.929306\"\n x=\"11.242865\"\n style=\"stroke-width:0.32272473\">GND</tspan>\n </text>\n <ellipse\n style=\"fill:#ffffff;stroke:#000000;stroke-width:0.32272443\"\n cy=\"-5.9231954\"\n cx=\"-24.289902\"\n id=\"SCL\"\n transform=\"scale(-1)\"\n rx=\"3.23646\"\n ry=\"3.218055\"\n inkscape:label=\"#path5042-7-6-2\" />\n <text\n transform=\"matrix(0,1.0070833,-0.99296652,0,0,0)\"\n id=\"text5100-8-5-47\"\n y=\"-22.366781\"\n x=\"11.108133\"\n style=\"font-weight:400;font-size:6.13176918px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.32272473\"\n font-weight=\"400\"\n font-size=\"1.9\"\n letter-spacing=\"0\"\n word-spacing=\"0\">\n <tspan\n y=\"-22.366781\"\n x=\"11.108133\"\n id=\"tspan5098-2-4-5\"\n style=\"stroke-width:0.32272473\">SCL</tspan>\n </text>\n <ellipse\n style=\"fill:#ffffff;stroke:#000000;stroke-width:0.32272443\"\n cy=\"-5.5968285\"\n cx=\"-54.547421\"\n id=\"SDO\"\n transform=\"scale(-1)\"\n rx=\"3.23646\"\n ry=\"3.218055\"\n inkscape:label=\"#path5042-7-3\" />\n <text\n transform=\"matrix(0,1.0070833,-0.99296652,0,0,0)\"\n id=\"text5100-8-5-4-4\"\n y=\"-52.621964\"\n x=\"10.784061\"\n style=\"font-weight:400;font-size:6.13176918px;line-height:1.25;font-family:consolas;-inkscape-font-specification:consolas;letter-spacing:0;word-spacing:0;fill:#ffffff;stroke-width:0.32272473\"\n font-weight=\"400\"\n font-size=\"1.9\"\n letter-spacing=\"0\"\n word-spacing=\"0\">\n <tspan\n id=\"tspan5156-4\"\n y=\"-52.621964\"\n x=\"10.784061\"\n style=\"stroke-width:0.32272473\">SDO</tspan>\n </text>\n</svg>\n",
1252
- "pxt.json": "{\n \"name\": \"accelerometer\",\n \"description\": \"The accelerometer library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"accelerometer.cpp\",\n \"accelhw.cpp\",\n \"axis.h\",\n \"gesture.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\",\n \"pxtparts.json\",\n \"part.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"PXT_SUPPORT_LIS3DH\": 1,\n \"PXT_SUPPORT_MMA8453\": 1,\n \"PXT_SUPPORT_MPU6050\": 1\n }\n },\n \"hidden\": true\n}\n",
1252
+ "pxt.json": "{\n \"name\": \"accelerometer\",\n \"description\": \"The accelerometer library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"accelerometer.cpp\",\n \"accelhw.cpp\",\n \"axis.h\",\n \"gesture.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\",\n \"pxtparts.json\",\n \"part.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"PXT_SUPPORT_LIS3DH\": 1,\n \"PXT_SUPPORT_MMA8453\": 1,\n \"PXT_SUPPORT_MPU6050\": 1\n }\n },\n \"hidden\": true\n}\n",
1253
1253
  "pxtparts.json": "{\n \"accelerometer\": {\n \"visual\": {\n \"image\": \"part.svg\",\n \"width\": 92.83499908447266,\n \"height\": 48.351558685302734,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 6.009125520265597,\n \"y\": 2.705139350474586\n },\n {\n \"x\": 36.0982164424424,\n \"y\": 2.705139350474586\n },\n {\n \"x\": 66.81896669097237,\n \"y\": 2.705139350474586\n },\n {\n \"x\": 81.86351733614008,\n \"y\": 2.705139350474586\n },\n {\n \"x\": 21.053670981354,\n \"y\": 2.705139350474586\n },\n {\n \"x\": 51.31091788377569,\n \"y\": 2.378772674719472\n }\n ]\n },\n \"numberOfPins\": 6,\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ACCELEROMETER_INT\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"SDA\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"SCL\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"assembly\": [\n {\n \"pinIndices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5\n ]\n }\n ]\n }\n}",
1254
1254
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace input {\n\n /**\n * Do something when a gesture happens (like shaking the board).\n * @param gesture the type of gesture to track, eg: Gesture.Shake\n * @param body code to run when gesture is raised\n */\n //% help=input/on-gesture\n //% blockId=device_gesture_event block=\"on |%NAME\"\n //% parts=\"accelerometer\"\n //% gesture.fieldEditor=\"gridpicker\"\n //% gesture.fieldOptions.width=220\n //% gesture.fieldOptions.columns=3\n //% weight=92 blockGap=12 shim=input::onGesture\n function onGesture(gesture: Gesture, body: () => void): void;\n\n /**\n * Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up,\n * x=0, y=0 and z=-1023)\n * @param dimension TODO\n */\n //% help=input/acceleration\n //% blockId=device_acceleration block=\"acceleration (mg)|%NAME\"\n //% parts=\"accelerometer\"\n //% dimension.fieldEditor=\"gridpicker\"\n //% dimension.fieldOptions.width=180\n //% dimension.fieldOptions.columns=2\n //% weight=42 blockGap=8 shim=input::acceleration\n function acceleration(dimension: Dimension): int32;\n\n /**\n * The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees.\n * @param kind TODO\n */\n //% help=input/rotation\n //% blockId=device_get_rotation block=\"rotation (°)|%NAME\"\n //% parts=\"accelerometer\"\n //% group=\"More\" weight=38 shim=input::rotation\n function rotation(kind: Rotation): int32;\n\n /**\n * Sets the accelerometer sample range in gravities.\n * @param range a value describe the maximum strengh of acceleration measured\n */\n //% help=input/set-accelerometer-range\n //% blockId=device_set_accelerometer_range block=\"set accelerometer|range %range\"\n //% weight=5\n //% parts=\"accelerometer\"\n //% group=\"More\" weight=15 blockGap=8 shim=input::setAccelerometerRange\n function setAccelerometerRange(range: AcceleratorRange): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
1255
1255
  "test.ts": ""
@@ -1257,7 +1257,7 @@ var pxtTargetBundle = {
1257
1257
  "azureiot": {
1258
1258
  "README.md": "# Azure IoT support - beta\n\nAzure MQTT communication layer. \nA port of https://github.com/rovale/micro-mqtt for MakeCode.\n\n## Settings\n\nThe connection string should be stored in the \"azureiot\" secret in the settings.",
1259
1259
  "azureiot.ts": "const enum AzureIotEvent {\n Connected = 1,\n Disconnected = 2,\n Error = 3,\n GotTwinResponse = 100,\n}\n\nnamespace azureiot {\n export const SECRETS_KEY = \"azureiot\"\n\n export let logPriority = ConsolePriority.Debug;\n\n type SMap<T> = { [s: string]: T; }\n export type Json = any;\n\n let _mqttClient: mqtt.Client;\n let _messageBusId: number;\n let _receiveHandler: (msg: Json, sysProps: SMap<string>) => void;\n let _methodHandlers: SMap<(msg: Json) => Json>;\n let twinRespHandlers: SMap<(status: number, body: any) => void>\n\n function log(msg: string) {\n console.add(logPriority, \"azureiot: \" + msg);\n }\n\n export function mqttClient(skipCreate?: boolean): mqtt.Client {\n if (!_mqttClient && !skipCreate) {\n log(\"creating mqtt client\")\n _mqttClient = createMQTTClient();\n }\n return _mqttClient;\n }\n\n function generateSasToken(resourceUri: string, signingKey: string, expiresEpoch: number) {\n const key = Buffer.fromBase64(signingKey)\n resourceUri = net.urlencode(resourceUri)\n const toSign = resourceUri + \"\\n\" + expiresEpoch\n const sig = net.urlencode(crypto.sha256Hmac(key, Buffer.fromUTF8(toSign)).toBase64())\n const token = `sr=${resourceUri}&se=${expiresEpoch}&sig=${sig}`\n return token\n }\n\n export function hubName() {\n return connectionStringPart(\"HostName\")\n }\n\n export function hubDeviceId() {\n return connectionStringPart(\"DeviceId\")\n }\n\n function messageBusId() {\n if (!_messageBusId)\n _messageBusId = control.allocateEventSource();\n return _messageBusId\n }\n\n function createMQTTClient() {\n messageBusId()\n const iotHubHostName = hubName()\n const deviceId = hubDeviceId()\n if (!iotHubHostName || !deviceId)\n throw \"invalid connection string\"\n\n const connStringParts = parseConnectionString();\n let sasToken = connStringParts[\"SharedAccessSignature\"];\n if (!sasToken)\n // token valid until year 2255; in future we may try something more short-lived\n sasToken = generateSasToken(`${iotHubHostName}/devices/${deviceId}`, connStringParts[\"SharedAccessKey\"], 9000000000)\n\n const opts: mqtt.IConnectionOptions = {\n host: iotHubHostName,\n /* port: 8883, overriden based on platform */\n username: `${iotHubHostName}/${deviceId}/?api-version=2018-06-30`,\n password: \"SharedAccessSignature \" + sasToken,\n clientId: deviceId\n }\n const c = new mqtt.Client(opts);\n const evid = messageBusId()\n c.on('connected', () => {\n log(\"connected\")\n control.raiseEvent(evid, AzureIotEvent.Connected)\n });\n c.on('disconnected', () => {\n log(\"disconnected\")\n control.raiseEvent(evid, AzureIotEvent.Disconnected)\n });\n c.on('error', (msg) => {\n log(\"error: \" + msg)\n control.raiseEvent(evid, AzureIotEvent.Error)\n });\n c.on('receive', (packet: mqtt.IMessage) => {\n log(\"unhandled msg: \" + packet.topic + \" / \" + packet.content.toString())\n });\n c.connect();\n return c;\n }\n\n function splitPair(kv: string): string[] {\n const i = kv.indexOf('=');\n if (i < 0)\n return [kv, \"\"];\n else\n return [kv.slice(0, i), kv.slice(i + 1)];\n }\n\n function parsePropertyBag(msg: string, separator?: string): SMap<string> {\n const r: SMap<string> = {};\n if (msg && typeof msg === \"string\")\n msg.split(separator || \"&\")\n .map(kv => splitPair(kv))\n .filter(parts => !!parts[1].length)\n .forEach(parts => r[net.urldecode(parts[0])] = net.urldecode(parts[1]));\n return r;\n }\n\n function parseConnectionString() {\n try {\n const connString = settings.programSecrets.readSecret(SECRETS_KEY);\n const connStringParts = parsePropertyBag(connString, \";\");\n return connStringParts\n } catch {\n console.debug(`clearing invalid azure iot connection string`)\n settings.programSecrets.setSecret(SECRETS_KEY, \"\")\n return {}\n }\n }\n\n function connectionStringPart(name: string) {\n const connStringParts = parseConnectionString()\n const value = connStringParts[name];\n return value || \"\"\n }\n\n function encodeQuery(props: SMap<string>): string {\n const keys = Object.keys(props)\n if (keys.length == 0)\n return \"\"\n return \"?\" + keys\n .map(k => `${net.urlencode(k)}=${net.urlencode(props[k])}`)\n .join('&');\n }\n\n export function setConnectionString(connectionString: string) {\n disconnect()\n settings.programSecrets.setSecret(SECRETS_KEY, connectionString)\n parseConnectionString()\n }\n\n /**\n * Disconnects the hub if any\n */\n export function disconnect() {\n const c = mqttClient(true)\n if (c) {\n try {\n c.disconnect()\n }\n catch {\n // just ignore errors disconnecting\n }\n }\n }\n\n /**\n * Connects to the IoT hub\n */\n export function connect() {\n const c = mqttClient();\n if (!c.connected) {\n c.connect() // start connect if not started yet\n // busy wait for connection\n const start = control.millis()\n const timeout = 30000\n while (!c.connected && control.millis() - start < timeout) {\n pause(1000)\n }\n if (!c.connected)\n throw \"connection failed\"\n }\n }\n\n /**\n * Registers code when the MQTT client gets connected or disconnected\n * @param event \n * @param handler \n */\n export function onEvent(event: AzureIotEvent, handler: () => void) {\n const evid = messageBusId()\n control.onEvent(evid, event, handler);\n try {\n const c = mqttClient(true);\n if (c && c.connected) // raise connected event by default\n control.raiseEvent(evid, AzureIotEvent.Connected);\n } catch { }\n }\n\n /**\n * Indicates if the MQTT client is connected\n */\n //%\n export function isConnected(): boolean {\n try {\n const c = mqttClient(true);\n return !!c && !!c.connected;\n }\n catch {\n return false\n }\n }\n\n /**\n * Send a message via mqtt\n * @param msg \n */\n //%\n export function publishMessageJSON(msg: Json, sysProps?: SMap<string>) {\n const c = mqttClient();\n let topic = `devices/${c.opt.clientId}/messages/events/`;\n if (sysProps)\n topic += encodeQuery(sysProps);\n const m = JSON.stringify(msg)\n msg = null\n // qos, retained are not supported\n c.publish(topic, m);\n }\n\n /**\n * Send a message via mqtt\n * @param msg \n */\n //%\n export function publishMessageBuffer(msg: Buffer, sysProps?: SMap<string>) {\n const c = mqttClient();\n let topic = `devices/${c.opt.clientId}/messages/events/`;\n if (sysProps)\n topic += encodeQuery(sysProps);\n // qos, retained are not supported\n c.publish(topic, msg);\n }\n\n /**\n * Send a message via mqtt\n * @param msg \n */\n //%\n export function publishMessageHex(msg: Buffer, len?: number, sysProps?: SMap<string>) {\n const c = mqttClient();\n let topic = `devices/${c.opt.clientId}/messages/events/`;\n if (sysProps)\n topic += encodeQuery(sysProps);\n if (len == null)\n len = msg.length\n if (len > msg.length) {\n log(`len too long: ${len}/${msg.length}`)\n len = msg.length\n }\n // qos, retained are not supported\n if (c.startPublish(topic, len * 2)) {\n const chunk = 128\n for (let ptr = 0; ptr < len; ptr += chunk)\n c.continuePublish(Buffer.fromUTF8(msg.slice(ptr, Math.min(chunk, len - ptr)).toHex()))\n c.finishPublish()\n }\n }\n\n /**\n * Registers code to run when a message is received\n * @param handler \n */\n //%\n export function onMessageReceived(handler: (body: Json, sysProps: SMap<string>) => void) {\n const c = mqttClient();\n if (!_receiveHandler) {\n c.subscribe(`devices/${c.opt.clientId}/messages/devicebound/#`, handleDeviceBound);\n\n /*\n c.subscribe('$iothub/twin/PATCH/properties/desired/#')\n */\n }\n _receiveHandler = handler;\n }\n\n function parseTopicArgs(topic: string) {\n const qidx = topic.indexOf(\"?\")\n if (qidx >= 0)\n return parsePropertyBag(topic.slice(qidx + 1))\n return {}\n }\n\n function handleDeviceBound(packet: mqtt.IMessage) {\n if (!_receiveHandler) return; // nobody's listening\n // TODO this needs some testing\n const sysProps = parseTopicArgs(packet.topic)\n _receiveHandler(JSON.parse(packet.content.toString()), sysProps);\n }\n\n function handleMethod(msg: mqtt.IMessage) {\n const props = parseTopicArgs(msg.topic)\n const qidx = msg.topic.indexOf(\"/?\")\n const methodName = msg.topic.slice(21, qidx)\n log(\"method: '\" + methodName + \"'; \" + JSON.stringify(props))\n let status = 200\n let resp: any = {}\n if (!_methodHandlers[methodName]) {\n log(\"method not found: '\" + methodName + \"'\")\n status = 404\n } else {\n const h = _methodHandlers[methodName]\n const resp2 = h(JSON.parse(msg.content.toString()))\n if (resp2)\n resp = resp2\n if (resp[\"_status\"] != null) {\n status = resp[\"_status\"]\n resp[\"_status\"] = undefined\n }\n log(\"method: '\" + methodName + \"' status=\" + status)\n }\n\n const c = mqttClient();\n c.publish('$iothub/methods/res/' + status + \"/?$rid=\" + props[\"$rid\"], JSON.stringify(resp))\n }\n\n // $iothub/twin/res/{status}/?$rid={request id}\n function twinResponse(msg: mqtt.IMessage) {\n const args = parseTopicArgs(msg.topic)\n const h = twinRespHandlers[args[\"$rid\"]]\n const status = parseInt(msg.topic.slice(17))\n // log(`twin resp: ${status} ${msg.content.toHex()} ${msg.content.toString()}`)\n if (h) {\n delete twinRespHandlers[args[\"$rid\"]]\n h(status, JSON.parse(msg.content.toString() || \"{}\"))\n }\n }\n\n export class ValueAwaiter {\n private evid: number\n private value: any\n constructor() {\n this.evid = control.allocateNotifyEvent()\n }\n setValue(v: any) {\n this.value = v\n control.raiseEvent(DAL.DEVICE_ID_NOTIFY, this.evid)\n this.evid = -1\n }\n wait() {\n if (this.evid < 0) return this.value\n control.waitForEvent(DAL.DEVICE_ID_NOTIFY, this.evid)\n return this.value\n }\n }\n\n function twinReq(path: string, msg?: string): Json {\n const c = mqttClient();\n if (!twinRespHandlers) {\n twinRespHandlers = {}\n c.subscribe(\"$iothub/twin/res/#\", twinResponse)\n }\n const rid = Math.randomRange(100000000, 900000000) + \"\"\n const va = new ValueAwaiter()\n twinRespHandlers[rid] = (status, body) => {\n if (status == 204 || status == 200) {\n va.setValue(body)\n } else {\n log(`twin error -> ${status} ${JSON.stringify(body)}`)\n va.setValue(null)\n }\n }\n c.publish(`$iothub/twin/${path}/?$rid=${rid}`, msg)\n return va.wait()\n }\n\n export function getTwin(): Json {\n return twinReq(\"GET\")\n }\n\n export function patchTwin(patch: Json) {\n const p = JSON.stringify(patch)\n if (p == \"{}\")\n log(\"skipping empty twin patch\")\n else {\n log(`twin patch: ${JSON.stringify(patch)}`)\n twinReq(\"PATCH/properties/reported\", p)\n }\n }\n\n export function computePatch(curr: Json, target: Json) {\n const patch: Json = {}\n for (const k of Object.keys(curr)) {\n const vt = target[k]\n if (k[0] == \"$\")\n continue\n if (vt === undefined) {\n patch[k] = null\n } else {\n const vc = curr[k]\n if (typeof vt == \"object\")\n if (typeof vc == \"object\") {\n const p0 = computePatch(vc, vt)\n if (Object.keys(p0).length > 0)\n patch[k] = p0\n } else {\n patch[k] = vt\n }\n else if (vc != vt)\n patch[k] = vt\n }\n }\n for (const k of Object.keys(target)) {\n if (curr[k] === undefined && k[0] != \"$\")\n patch[k] = target[k]\n }\n return patch\n }\n\n export function applyPatch(trg: Json, patch: Json) {\n for (const k of Object.keys(patch)) {\n const v = patch[k]\n if (v === null) {\n delete trg[k]\n } else if (typeof v == \"object\") {\n if (!trg[k]) trg[k] = {}\n applyPatch(trg[k], v)\n } else {\n trg[k] = v\n }\n }\n }\n\n export function onTwinUpdate(handler: (twin: Json, patch: Json) => void) {\n const c = mqttClient()\n let currTwin: Json = null\n let lastVersion: number\n c.subscribe(\"$iothub/twin/PATCH/properties/desired/#\", msg => {\n if (!currTwin)\n return\n const sysProps = parseTopicArgs(msg.topic)\n const ver = parseInt(sysProps[\"$version\"])\n if (ver <= lastVersion) {\n log(`skipping twin update: ${ver}`)\n return\n }\n const update = JSON.parse(msg.content.toString())\n applyPatch(currTwin[\"desired\"], update)\n handler(currTwin, update)\n })\n currTwin = getTwin()\n lastVersion = currTwin[\"desired\"][\"$version\"]\n handler(currTwin, currTwin[\"desired\"])\n }\n\n export function onMethod(methodName: string, handler: (msg: Json) => Json) {\n const c = mqttClient();\n if (!_methodHandlers) {\n if (!c.connected)\n throw \"azure iot hub not connected\"\n _methodHandlers = {}\n c.subscribe('$iothub/methods/POST/#', handleMethod)\n }\n _methodHandlers[methodName] = handler\n }\n}\n",
1260
- "pxt.json": "{\n \"name\": \"azureiot\",\n \"description\": \"Azure IoT - beta\",\n \"dependencies\": {\n \"mqtt\": \"*\",\n \"settings\": \"*\"\n },\n \"files\": [\n \"azureiot.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"testDependencies\": {\n \"esp32\": \"file:../esp32\"\n },\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1260
+ "pxt.json": "{\n \"name\": \"azureiot\",\n \"description\": \"Azure IoT - beta\",\n \"dependencies\": {\n \"mqtt\": \"*\",\n \"settings\": \"*\"\n },\n \"files\": [\n \"azureiot.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"testDependencies\": {\n \"esp32\": \"file:../esp32\"\n },\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1261
1261
  "test.ts": "function test() {\n\n const log = console.log;\n const esp = net.instance().controller();\n\n if (!esp.connect()) {\n log(\"can't connect\")\n return\n }\n\n log(\"ping: \" + esp.ping(\"bing.com\"))\n\n azureiot.connect()\n log(\"mqtt connected\")\n\n azureiot.onMessageReceived((msg) => {\n log(\"MSG:\" + JSON.stringify(msg))\n })\n\n azureiot.onMethod(\"echo\", msg => {\n log(\"ECHO \" + msg.displayedValue)\n msg.type = \"echo\"\n return {}\n })\n}\n\ntest();"
1262
1262
  },
1263
1263
  "base": {
@@ -1289,7 +1289,7 @@ var pxtTargetBundle = {
1289
1289
  "pxt-core.d.ts": "/// <reference no-default-lib=\"true\"/>\n\ninterface Array<T> {\n /**\n * Get or set the length of an array. This number is one more than the index of the last element the array.\n */\n //% shim=Array_::length weight=84\n //% blockId=\"lists_length\" block=\"length of %VALUE\" blockBuiltin=true blockNamespace=\"arrays\"\n length: number;\n\n /**\n * Append a new element to an array.\n * @param items New elements of the Array.\n */\n //% help=arrays/push\n //% shim=Array_::push weight=50\n //% blockId=\"array_push\" block=\"%list| add value %value| to end\" blockNamespace=\"arrays\"\n //% group=\"Modify\"\n push(item: T): void;\n\n /**\n * Concatenates the values with another array.\n * @param arr The other array that is being concatenated with\n */\n //% helper=arrayConcat weight=40\n concat(arr: T[]): T[];\n\n /**\n * Remove the last element from an array and return it.\n */\n //% help=arrays/pop\n //% shim=Array_::pop weight=45\n //% blockId=\"array_pop\" block=\"get and remove last value from %list\" blockNamespace=\"arrays\"\n //% group=\"Read\"\n pop(): T;\n\n /**\n * Reverse the elements in an array. The first array element becomes the last, and the last array element becomes the first.\n */\n //% help=arrays/reverse\n //% helper=arrayReverse weight=10\n //% blockId=\"array_reverse\" block=\"reverse %list\" blockNamespace=\"arrays\"\n //% group=\"Operations\"\n reverse(): void;\n\n /**\n * Remove the first element from an array and return it. This method changes the length of the array.\n */\n //% help=arrays/shift\n //% helper=arrayShift weight=30\n //% blockId=\"array_shift\" block=\"get and remove first value from %list\" blockNamespace=\"arrays\"\n //% group=\"Read\"\n shift(): T;\n\n /**\n * Add one element to the beginning of an array and return the new length of the array.\n * @param element to insert at the start of the Array.\n */\n //% help=arrays/unshift\n //% helper=arrayUnshift weight=25\n //% blockId=\"array_unshift\" block=\"%list| insert %value| at beginning\" blockNamespace=\"arrays\"\n //% group=\"Modify\"\n //unshift(...values:T[]): number; //rest is not supported in our compiler yet.\n unshift(value: T): number;\n\n /**\n * Return a section of an array.\n * @param start The beginning of the specified portion of the array. eg: 0\n * @param end The end of the specified portion of the array. eg: 0\n */\n //% help=arrays/slice\n //% helper=arraySlice weight=41 blockNamespace=\"arrays\"\n slice(start?: number, end?: number): T[];\n\n /**\n * Remove elements from an array.\n * @param start The zero-based location in the array from which to start removing elements. eg: 0\n * @param deleteCount The number of elements to remove. eg: 0\n */\n //% helper=arraySplice weight=40\n splice(start: number, deleteCount: number): void;\n\n /**\n * joins all elements of an array into a string and returns this string.\n * @param sep the string separator\n */\n //% helper=arrayJoin weight=40\n join(sep?: string): string;\n\n /**\n * Tests whether at least one element in the array passes the test implemented by the provided function.\n * @param callbackfn A function that accepts up to two arguments. The some method calls the callbackfn function one time for each element in the array.\n */\n //% helper=arraySome weight=40\n some(callbackfn: (value: T, index: number) => boolean): boolean;\n\n /**\n * Tests whether all elements in the array pass the test implemented by the provided function.\n * @param callbackfn A function that accepts up to two arguments. The every method calls the callbackfn function one time for each element in the array.\n */\n //% helper=arrayEvery weight=40\n every(callbackfn: (value: T, index: number) => boolean): boolean;\n\n /**\n * Sort the elements of an array in place and returns the array. The sort is not necessarily stable.\n * @param specifies a function that defines the sort order. If omitted, the array is sorted according to the prmitive type\n */\n //% helper=arraySort weight=40\n sort(callbackfn?: (value1: T, value2: T) => number): T[];\n\n /**\n * Call a defined callback function on each element of an array, and return an array containing the results.\n * @param callbackfn A function that accepts up to two arguments. The map method calls the callbackfn function one time for each element in the array.\n */\n //% helper=arrayMap weight=40\n map<U>(callbackfn: (value: T, index: number) => U): U[];\n\n /**\n * Call a defined callback function on each element of an array.\n * @param callbackfn A function that accepts up to two arguments. The forEach method calls the callbackfn function one time for each element in the array.\n */\n //% helper=arrayForEach weight=40\n forEach(callbackfn: (value: T, index: number) => void): void;\n\n /**\n * Return the elements of an array that meet the condition specified in a callback function.\n * @param callbackfn A function that accepts up to two arguments. The filter method calls the callbackfn function one time for each element in the array.\n */\n //% helper=arrayFilter weight=40\n filter(callbackfn: (value: T, index: number) => boolean): T[];\n\n /**\n * Fills all the elements of an array from a start index to an end index with a static value. The end index is not included.\n */\n //% helper=arrayFill weight=39\n fill(value: T, start?: number, end?: number): T[];\n\n /**\n * Returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.\n * @param callbackfn\n */\n //% helper=arrayFind weight=40\n find(callbackfn: (value: T, index: number) => boolean): T;\n\n /**\n * Call the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.\n * @param callbackfn A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the array.\n * @param initialValue Initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.\n */\n //% helper=arrayReduce weight=40\n reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number) => U, initialValue: U): U;\n\n\n /** Remove the first occurence of an object. Returns true if removed. */\n //% shim=Array_::removeElement weight=48\n removeElement(element: T): boolean;\n\n /** Remove the element at a certain index. */\n //% help=arrays/remove-at\n //% shim=Array_::removeAt weight=47\n //% blockId=\"array_removeat\" block=\"%list| get and remove value at %index\" blockNamespace=\"arrays\"\n //% group=\"Read\"\n removeAt(index: number): T;\n\n /**\n * Insert the value at a particular index, increases length by 1\n * @param index the zero-based position in the list to insert the value, eg: 0\n * @param the value to insert, eg: 0\n */\n //% help=arrays/insert-at\n //% shim=Array_::insertAt weight=20\n //% blockId=\"array_insertAt\" block=\"%list| insert at %index| value %value\" blockNamespace=\"arrays\"\n //% group=\"Modify\"\n insertAt(index: number, value: T): void;\n\n /**\n * Return the index of the first occurrence of a value in an array.\n * @param item The value to locate in the array.\n * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.\n */\n //% help=arrays/index-of\n //% shim=Array_::indexOf weight=40\n //% blockId=\"array_indexof\" block=\"%list| find index of %value\" blockNamespace=\"arrays\"\n //% group=\"Operations\"\n indexOf(item: T, fromIndex?: number): number;\n\n /**\n * Get the value at a particular index\n * @param index the zero-based position in the list of the item, eg: 0\n */\n //% help=arrays/get\n //% shim=Array_::getAt weight=85\n get(index: number): T;\n\n /**\n * Store a value at a particular index\n * @param index the zero-based position in the list to store the value, eg: 0\n * @param value the value to insert, eg: 0\n */\n //% help=arrays/set\n //% shim=Array_::setAt weight=84\n set(index: number, value: T): void;\n\n /**\n * Return a random value from the array\n */\n //% help=arrays/pick-random\n //% helper=arrayPickRandom weight=25\n //% blockId=\"array_pickRandom\" block=\"get random value from %list\"\n //% blockNamespace=\"arrays\"\n //% group=\"Read\"\n _pickRandom(): T;\n\n [n: number]: T;\n\n /**\n * Add one element to the beginning of an array and return the new length of the array.\n * @param element to insert at the start of the Array.\n */\n //% help=arrays/unshift\n //% helper=arrayUnshift weight=24\n //% blockId=\"array_unshift_statement\" block=\"%list| insert %value| at beginning\" blockNamespace=\"arrays\"\n //% blockAliasFor=\"Array.unshift\"\n //% group=\"Modify\"\n _unshiftStatement(value: T): void;\n\n /**\n * Remove the last element from an array and return it.\n */\n //% help=arrays/pop\n //% shim=Array_::pop weight=44\n //% blockId=\"array_pop_statement\" block=\"remove last value from %list\" blockNamespace=\"arrays\"\n //% blockAliasFor=\"Array.pop\"\n //% group=\"Modify\"\n _popStatement(): void;\n\n /**\n * Remove the first element from an array and return it. This method changes the length of the array.\n */\n //% help=arrays/shift\n //% helper=arrayShift weight=29\n //% blockId=\"array_shift_statement\" block=\"remove first value from %list\" blockNamespace=\"arrays\"\n //% blockAliasFor=\"Array.shift\"\n //% group=\"Modify\"\n _shiftStatement(): void;\n\n /** Remove the element at a certain index. */\n //% help=arrays/remove-at\n //% shim=Array_::removeAt weight=14\n //% blockId=\"array_removeat_statement\" block=\"%list| remove value at %index\" blockNamespace=\"arrays\"\n //% blockAliasFor=\"Array.removeAt\"\n //% group=\"Modify\"\n _removeAtStatement(index: number): void;\n}\n\ndeclare interface String {\n // This block is currently disabled in favor of the built-in Blockly \"Create text with\" block, which compiles to \"\" + \"\"\n // Add % sign back to the block annotation to re-enable\n /**\n * Returns a string that contains the concatenation of two or more strings.\n * @param other The string to append to the end of the string.\n */\n //% shim=String_::concat weight=49\n //% blockId=\"string_concat\" blockNamespace=\"text\"\n // block=\"join %list=text|%other\"\n concat(other: string): string;\n\n /**\n * Return the character at the specified index.\n * @param index The zero-based index of the desired character.\n */\n //% shim=String_::charAt weight=48\n //% help=text/char-at\n //% blockId=\"string_get\" block=\"char from %this=text|at %pos\" blockNamespace=\"text\"\n charAt(index: number): string;\n\n /** Returns the length of a String object. */\n //% property shim=String_::length weight=47\n //% blockId=\"text_length\" block=\"length of %VALUE\" blockBuiltin=true blockNamespace=\"text\"\n length: number;\n\n /**\n * Return the Unicode value of the character at the specified location.\n * @param index The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.\n */\n //% shim=String_::charCodeAt\n charCodeAt(index: number): number;\n\n /**\n * See how the order of characters in two strings is different (in ASCII encoding).\n * @param that String to compare to target string\n */\n //% shim=String_::compare\n //% help=text/compare\n //% blockId=\"string_compare\" block=\"compare %this=text| to %that\" blockNamespace=\"text\"\n compare(that: string): number;\n\n /**\n * Return a substring of the current string.\n * @param start first character index; can be negative from counting from the end, eg:0\n * @param length number of characters to extract, eg: 10\n */\n //% helper=stringSubstr\n //% help=text/substr\n //% blockId=\"string_substr\" block=\"substring of %this=text|from %start|of length %length\" blockNamespace=\"text\"\n substr(start: number, length?: number): string;\n\n /**\n * Return the current string with the first occurence of toReplace\n * replaced with the replacer\n * @param toReplace the substring to replace in the current string\n * @param replacer either the string that replaces toReplace in the current string,\n * or a function that accepts the substring and returns the replacement string.\n */\n //% helper=stringReplace\n replace(toReplace: string, replacer: string | ((sub: string) => string)): string;\n\n /**\n * Return the current string with each occurence of toReplace\n * replaced with the replacer\n * @param toReplace the substring to replace in the current string\n * @param replacer either the string that replaces toReplace in the current string,\n * or a function that accepts the substring and returns the replacement string.\n */\n //% helper=stringReplaceAll\n replaceAll(toReplace: string, replacer: string | ((sub: string) => string)): string;\n\n /**\n * Return a substring of the current string.\n * @param start first character index; can be negative from counting from the end, eg:0\n * @param end one-past-last character index\n */\n //% helper=stringSlice\n slice(start: number, end?: number): string;\n\n /** Returns a value indicating if the string is empty */\n //% helper=stringEmpty\n //% help=text/is-empty\n //% blockId=\"string_isempty\" blockNamespace=\"text\"\n //% block=\"%this=text| is empty\"\n isEmpty(): boolean;\n\n /**\n * Returns the position of the first occurrence of a specified value in a string.\n * @param searchValue the text to find\n * @param start optional start index for the search\n */\n //% shim=String_::indexOf\n //% help=text/index-of\n //% blockId=\"string_indexof\" blockNamespace=\"text\"\n //% block=\"%this=text|find index of %searchValue\"\n indexOf(searchValue: string, start?: number): number;\n\n /**\n * Determines whether a string contains the characters of a specified string.\n * @param searchValue the text to find\n * @param start optional start index for the search\n */\n //% shim=String_::includes\n //% help=text/includes\n //% blockId=\"string_includes\" blockNamespace=\"text\"\n //% block=\"%this=text|includes %searchValue\"\n includes(searchValue: string, start?: number): boolean;\n\n /**\n * Splits the string according to the separators\n * @param separator\n * @param limit\n */\n //% helper=stringSplit\n //% help=text/split\n //% blockId=\"string_split\" blockNamespace=\"text\"\n //% block=\"split %this=text|at %separator\"\n split(separator?: string, limit?: number): string[];\n\n /**\n * Return a substring of the current string with whitespace removed from both ends\n */\n //% helper=stringTrim\n trim(): string;\n\n /**\n * Converts the string to upper case characters.\n */\n //% helper=stringToUpperCase\n //% help=text/to-upper-case\n toUpperCase(): string;\n\n /**\n * Converts the string to lower case characters.\n */\n //% helper=stringToLowerCase\n //% help=text/to-lower-case\n toLowerCase(): string;\n\n [index: number]: string;\n}\n\n/**\n * Convert a string to a number.\n * @param s A string to convert into a number. eg: 123\n */\n//% shim=String_::toNumber\n//% help=text/parse-float\n//% blockId=\"string_parsefloat\" block=\"parse to number %text\" blockNamespace=\"text\"\n//% text.defl=\"123\"\ndeclare function parseFloat(text: string): number;\n\n/**\n * Returns a pseudorandom number between min and max included.\n * If both numbers are integral, the result is integral.\n * @param min the lower inclusive bound, eg: 0\n * @param max the upper inclusive bound, eg: 10\n */\n//% blockId=\"device_random\" block=\"pick random %min|to %limit\"\n//% blockNamespace=\"Math\"\n//% help=math/randint\n//% shim=Math_::randomRange\ndeclare function randint(min: number, max: number): number;\n\ninterface Object { }\ninterface Function {\n __assignableToFunction: Function;\n}\ninterface IArguments {\n __assignableToIArguments: IArguments;\n}\ninterface RegExp {\n __assignableToRegExp: RegExp;\n}\ntype TemplateStringsArray = Array<string>;\n\ntype uint8 = number;\ntype uint16 = number;\ntype uint32 = number;\ntype int8 = number;\ntype int16 = number;\ntype int32 = number;\n\n\ndeclare interface Boolean {\n /**\n * Returns a string representation of an object.\n */\n //% shim=numops::toString\n toString(): string;\n}\n\n/**\n * Combine, split, and search text strings.\n*/\n//% blockNamespace=\"text\"\ndeclare namespace String {\n\n /**\n * Make a string from the given ASCII character code.\n */\n //% help=math/from-char-code\n //% shim=String_::fromCharCode weight=1\n //% blockNamespace=\"text\" blockId=\"stringFromCharCode\" block=\"text from char code %code\"\n function fromCharCode(code: number): string;\n}\n\ndeclare interface Number {\n /**\n * Returns a string representation of a number.\n */\n //% shim=numops::toString\n toString(): string;\n}\n\n/**\n * Add, remove, and replace items in lists.\n*/\n//% blockNamespace=\"Arrays\"\ndeclare namespace Array {\n /**\n * Check if a given object is an array.\n */\n //% shim=Array_::isArray\n function isArray(obj: any): boolean;\n}\n\ndeclare namespace Object {\n /**\n * Return the field names in an object.\n */\n //% shim=pxtrt::keysOf\n function keys(obj: any): string[];\n}\n\n/**\n * More complex operations with numbers.\n*/\ndeclare namespace Math {\n /**\n * Returns the value of a base expression taken to a specified power.\n * @param x The base value of the expression.\n * @param y The exponent value of the expression.\n */\n //% shim=Math_::pow\n function pow(x: number, y: number): number;\n\n /**\n * Returns a pseudorandom number between 0 and 1.\n */\n //% shim=Math_::random\n //% help=math/random\n function random(): number;\n\n /**\n * Returns a pseudorandom number between min and max included.\n * If both numbers are integral, the result is integral.\n * @param min the lower inclusive bound, eg: 0\n * @param max the upper inclusive bound, eg: 10\n */\n //% blockId=\"device_random_deprecated\" block=\"pick random %min|to %limit\"\n //% help=math/random-range deprecated\n //% shim=Math_::randomRange\n function randomRange(min: number, max: number): number;\n\n /**\n * Returns the natural logarithm (base e) of a number.\n * @param x A number\n */\n //% shim=Math_::log\n //% help=math\n function log(x: number): number;\n\n /**\n * Returns returns ``e^x``.\n * @param x A number\n */\n //% shim=Math_::exp\n //% help=math\n function exp(x: number): number;\n\n /**\n * Returns the sine of a number.\n * @param x An angle in radians\n */\n //% shim=Math_::sin\n //% help=math/trigonometry\n function sin(x: number): number;\n\n /**\n * Returns the cosine of a number.\n * @param x An angle in radians\n */\n //% shim=Math_::cos\n //% help=math/trigonometry\n function cos(x: number): number;\n\n /**\n * Returns the tangent of a number.\n * @param x An angle in radians\n */\n //% shim=Math_::tan\n //% help=math/trigonometry\n function tan(x: number): number;\n\n /**\n * Returns the arcsine (in radians) of a number\n * @param x A number\n */\n //% shim=Math_::asin\n //% help=math/trigonometry\n function asin(x: number): number;\n\n /**\n * Returns the arccosine (in radians) of a number\n * @param x A number\n */\n //% shim=Math_::acos\n //% help=math/trigonometry\n function acos(x: number): number;\n\n /**\n * Returns the arctangent (in radians) of a number\n * @param x A number\n */\n //% shim=Math_::atan\n //% help=math/trigonometry\n function atan(x: number): number;\n\n /**\n * Returns the arctangent of the quotient of its arguments.\n * @param y A number\n * @param x A number\n */\n //% shim=Math_::atan2\n //% help=math/trigonometry\n function atan2(y: number, x: number): number;\n\n /**\n * Returns the square root of a number.\n * @param x A numeric expression.\n */\n //% shim=Math_::sqrt\n //% help=math\n function sqrt(x: number): number;\n\n /**\n * Returns the smallest number greater than or equal to its numeric argument.\n * @param x A numeric expression.\n */\n //% shim=Math_::ceil\n //% help=math\n function ceil(x: number): number;\n\n /**\n * Returns the greatest number less than or equal to its numeric argument.\n * @param x A numeric expression.\n */\n //% shim=Math_::floor\n //% help=math\n function floor(x: number): number;\n\n /**\n * Returns the number with the decimal part truncated.\n * @param x A numeric expression.\n */\n //% shim=Math_::trunc\n //% help=math\n function trunc(x: number): number;\n\n /**\n * Returns a supplied numeric expression rounded to the nearest number.\n * @param x The value to be rounded to the nearest number.\n */\n //% shim=Math_::round\n //% help=math\n function round(x: number): number;\n\n /**\n * Returns the value of integer signed 32 bit multiplication of two numbers.\n * @param x The first number\n * @param y The second number\n */\n //% shim=Math_::imul\n //% help=math\n function imul(x: number, y: number): number;\n\n /**\n * Returns the value of integer signed 32 bit division of two numbers.\n * @param x The first number\n * @param y The second number\n */\n //% shim=Math_::idiv\n //% help=math\n function idiv(x: number, y: number): number;\n}\n\ndeclare namespace control {\n //% shim=_control::_onCodeStart\n export function _onCodeStart(arg: any): void;\n\n //% shim=_control::_onCodeStop\n export function _onCodeStop(arg: any): void;\n}",
1290
1290
  "pxt-helpers.ts": "type Action = () => void;\n\n/**\n * Constant representing Not-A-Number.\n */\nconst NaN = 0 / 0\n\n/**\n * Constant representing positive infinity.\n */\nconst Infinity = 1 / 0\n\nfunction isNaN(x: number) {\n x = +x // convert to number\n return x !== x\n}\n\nnamespace Number {\n /**\n * Check if a given value is of type Number and it is a NaN.\n */\n export function isNaN(x: any): boolean {\n return typeof x == \"number\" && x !== x\n }\n}\n\n/**\n * A dictionary from string key to string values\n */\ninterface StringMap {\n [index: string]: string;\n}\n\n/**\n * Convert a string to an integer.\n * @param text A string to convert into an integral number. eg: \"123\"\n * @param radix optional A value between 2 and 36 that specifies the base of the number in text.\n * If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.\n * All other strings are considered decimal.\n */\n//% help=text/parse-int\n//% blockId=\"string_parseint\" block=\"parse to integer %text\" blockNamespace=\"text\"\n//% text.defl=\"123\"\n//% blockHidden=1\nfunction parseInt(text: string, radix?: number): number {\n // roughly based on https://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.2\n // with some consideration for avoiding unnecessary slices where easy\n if (!text || (radix != null && (radix < 2 || radix > 36)))\n return NaN;\n\n let start = 0;\n while (start < text.length && helpers.isWhitespace(text.charCodeAt(start)))\n ++start;\n\n if (start === text.length)\n return NaN;\n\n const numberOffset = 48; // 0\n const numCount = 10;\n const letterOffset = 97; // a\n const letterCount = 26;\n const lowerCaseMask = 0x20;\n\n let sign = 1;\n switch (text.charAt(start)) {\n case \"-\":\n sign = -1;\n // fallthrough\n case \"+\":\n ++start;\n }\n\n if ((!radix || radix == 16)\n && \"0\" === text[start]\n && (\"x\" === text[start + 1] || \"X\" === text[start + 1])) {\n radix = 16;\n start += 2;\n } else if (!radix) {\n radix = 10;\n }\n\n let output = 0;\n let hasDigit = false;\n for (let i = start; i < text.length; ++i) {\n const code = text.charCodeAt(i) | lowerCaseMask;\n let val: number = undefined;\n\n if (code >= numberOffset && code < numberOffset + numCount)\n val = code - numberOffset;\n else if (code >= letterOffset && code < letterOffset + letterCount)\n val = numCount + code - letterOffset;\n\n if (val == undefined || val >= radix) {\n if (!hasDigit) {\n return NaN;\n }\n break;\n }\n hasDigit = true;\n output = output * radix + val;\n }\n\n return sign * output;\n}\n\nnamespace helpers {\n export function arrayFill<T>(O: T[], value: T, start?: number, end?: number) {\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill\n // Steps 3-5.\n const len = O.length >>> 0;\n\n // Steps 6-7.\n const relativeStart = start === undefined ? 0 : start >> 0;\n\n // Step 8.\n let k = relativeStart < 0 ?\n Math.max(len + relativeStart, 0) :\n Math.min(relativeStart, len);\n\n // Steps 9-10.\n const relativeEnd = end === undefined ? len : end >> 0;\n\n // Step 11.\n const final = relativeEnd < 0 ?\n Math.max(len + relativeEnd, 0) :\n Math.min(relativeEnd, len);\n\n // Step 12.\n while (k < final) {\n O[k] = value;\n k++;\n }\n\n // Step 13.\n return O;\n }\n\n export function arraySplice<T>(arr: T[], start: number, len: number) {\n if (start < 0) {\n return;\n }\n for (let i = 0; i < len; ++i) {\n arr.removeAt(start)\n }\n }\n\n export function arrayReverse<T>(arr: T[]): void {\n let len = arr.length;\n for (let i = 0; i < len / 2; i++) {\n swap(arr, i, len - i - 1);\n }\n }\n\n export function arrayShift<T>(arr: T[]): T {\n return arr.removeAt(0);\n }\n\n export function arrayJoin<T>(arr: T[], sep?: string): string {\n if (sep === undefined || sep === null) {\n sep = \",\";\n }\n\n let r = \"\";\n let len = arr.length // caching this seems to match V8\n for (let i = 0; i < len; ++i) {\n if (i > 0 && sep)\n r += sep;\n r += (arr[i] === undefined || arr[i] === null) ? \"\" : arr[i];\n }\n return r;\n }\n\n /*TODO: Enable this multiple value unshift, after rest is enabled in our compiler.\n export function arrayUnshift<T>(arr: T[], ...values: T[]) : number {\n for(let i = values.length; i > 0; --i) {\n arr.insertAt(0, values[i - 1]);\n }\n return arr.length;\n }\n */\n export function arrayUnshift<T>(arr: T[], value: T): number {\n arr.insertAt(0, value);\n return arr.length;\n }\n\n function swap<T>(arr: T[], i: number, j: number): void {\n let temp: T = arr[i];\n arr[i] = arr[j];\n arr[j] = temp;\n }\n\n function sortHelper<T>(arr: T[], callbackfn?: (value1: T, value2: T) => number): T[] {\n if (arr.length <= 0 || !callbackfn) {\n return arr;\n }\n let len = arr.length;\n // simple selection sort.\n for (let i = 0; i < len - 1; ++i) {\n for (let j = i + 1; j < len; ++j) {\n if (callbackfn(arr[i], arr[j]) > 0) {\n swap(arr, i, j);\n }\n }\n }\n return arr;\n }\n\n export function arraySort<T>(arr: T[], callbackfn?: (value1: T, value2: T) => number): T[] {\n if (!callbackfn && arr.length > 1) {\n callbackfn = (a, b) => {\n // default is sort as if the element were a string, with null < undefined\n const aIsUndef = a === undefined;\n const bIsUndef = b === undefined;\n if (aIsUndef && bIsUndef) return 0;\n else if (aIsUndef) return 1;\n else if (bIsUndef) return -1;\n\n const aIsNull = a === null;\n const bIsNull = b === null;\n if (aIsNull && bIsNull) return 0;\n else if (aIsNull) return 1;\n else if (bIsNull) return -1;\n\n return (a + \"\").compare(b + \"\");\n }\n }\n return sortHelper(arr, callbackfn);\n }\n\n export function arrayMap<T, U>(arr: T[], callbackfn: (value: T, index: number) => U): U[] {\n let res: U[] = []\n let len = arr.length // caching this seems to match V8\n for (let i = 0; i < len; ++i) {\n res.push(callbackfn(arr[i], i))\n }\n return res\n }\n\n export function arraySome<T>(arr: T[], callbackfn: (value: T, index: number) => boolean): boolean {\n let len = arr.length // caching this seems to match V8\n for (let i = 0; i < len; ++i)\n if (callbackfn(arr[i], i))\n return true;\n return false;\n }\n\n export function arrayEvery<T>(arr: T[], callbackfn: (value: T, index: number) => boolean): boolean {\n let len = arr.length // caching this seems to match V8\n for (let i = 0; i < len; ++i)\n if (!callbackfn(arr[i], i))\n return false;\n return true;\n }\n\n export function arrayForEach<T>(arr: T[], callbackfn: (value: T, index: number) => void): void {\n let len = arr.length // caching this seems to match V8\n for (let i = 0; i < len; ++i) {\n callbackfn(arr[i], i);\n }\n }\n\n export function arrayFilter<T>(arr: T[], callbackfn: (value: T, index: number) => boolean): T[] {\n let res: T[] = []\n let len = arr.length\n for (let i = 0; i < len; ++i) {\n let v = arr[i] // need to cache\n if (callbackfn(v, i)) res.push(v)\n }\n return res\n }\n\n export function arrayFind<T>(arr: T[], callbackfn: (value: T, index: number) => boolean): T {\n let len = arr.length\n for (let i = 0; i < len; ++i) {\n let v = arr[i] // need to cache\n if (callbackfn(v, i)) return v;\n }\n return undefined;\n }\n\n export function arrayReduce<T, U>(arr: T[], callbackfn: (previousValue: U, currentValue: T, currentIndex: number) => U, initialValue: U): U {\n let len = arr.length\n for (let i = 0; i < len; ++i) {\n initialValue = callbackfn(initialValue, arr[i], i)\n }\n return initialValue\n }\n\n export function arrayConcat<T>(arr: T[], otherArr: T[]): T[] {\n let out: T[] = [];\n for (let value of arr) {\n out.push(value);\n }\n for (let value of otherArr) {\n out.push(value);\n }\n return out;\n }\n\n export function arrayPickRandom<T>(arr: T[]): T {\n return arr[Math.randomRange(0, arr.length - 1)];\n }\n\n export function arraySlice<T>(arr: T[], start?: number, end?: number): T[] {\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice\n const res: T[] = [];\n const len = arr.length;\n\n if (start === undefined)\n start = 0;\n else if (start < 0)\n start = Math.max(len + start, 0);\n\n if (start > len)\n return res;\n\n if (end === undefined)\n end = len;\n else if (end < 0)\n end = len + end;\n\n if (end > len)\n end = len;\n\n for (let i = start; i < end; ++i) {\n res.push(arr[i]);\n }\n return res;\n }\n\n export function stringReplace(s: string, toReplace: string, replacer: string | ((sub: string) => string)) {\n toReplace = toReplace + \"\";\n const ind = s.indexOf(toReplace);\n if (ind == -1)\n return s;\n\n const begin = s.slice(0, ind);\n const end = s.slice(ind + toReplace.length);\n\n if (typeof replacer == \"string\" || !replacer) {\n return begin + replacer + end;\n } else {\n return begin + replacer(toReplace) + end;\n }\n }\n\n export function stringReplaceAll(s: string, toReplace: string, replacer: string | ((sub: string) => string)) {\n toReplace = toReplace + \"\";\n const split = s.split(toReplace);\n const empty = toReplace.isEmpty();\n\n let output = (empty ? applyReplace(toReplace, replacer) : \"\");\n\n if (split.length) {\n output += split[0];\n }\n\n for (let i = 1; i < split.length; ++i) {\n output += applyReplace(toReplace, replacer) + split[i];\n }\n\n if (!s.isEmpty() && empty) {\n output += applyReplace(toReplace, replacer);\n }\n\n return output;\n\n function applyReplace(r: string, replacer: string | ((sub: string) => string)): string {\n if (typeof replacer == \"string\" || !replacer) {\n return replacer as string;\n } else {\n return replacer(r);\n }\n }\n }\n\n //% shim=String_::substr\n declare function stringSubstrHelper(s: string, start: number, length?: number): string;\n\n export function stringSubstr(s: string, start: number, length?: number): string {\n length = length === undefined ? s.length : length || 0;\n return stringSubstrHelper(s, start, length);\n }\n\n export function stringSlice(s: string, start: number, end?: number): string {\n const len = s.length;\n\n if (start < 0) {\n start = Math.max(len + start, 0);\n }\n\n if (end === undefined) {\n end = len;\n } else if (end === null) {\n end = 0;\n }\n\n if (end < 0) {\n end = len + end;\n }\n\n return stringSubstrHelper(s, start, end - start);\n }\n\n // also note this doesn't handle unicode, but neither does JS (there's toLocaleUpperCase())\n export function stringToUpperCase(s: string): string {\n let r = \"\"\n let prev = 0\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i)\n if (97 <= c && c <= 122) {\n r += s.slice(prev, i) + String.fromCharCode(c - 32)\n prev = i + 1\n }\n }\n r += s.slice(prev)\n return r\n }\n\n // also note this doesn't handle unicode, but neither does JS (there's toLocaleLowerCase())\n export function stringToLowerCase(s: string): string {\n let r = \"\"\n let prev = 0\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i)\n if (65 <= c && c <= 90) {\n r += s.slice(prev, i) + String.fromCharCode(c + 32)\n prev = i + 1\n }\n }\n r += s.slice(prev)\n return r\n }\n\n export function stringSplit(S: string, separator?: string, limit?: number): string[] {\n // https://www.ecma-international.org/ecma-262/6.0/#sec-string.prototype.split\n const A: string[] = [];\n let lim = 0;\n if (limit === undefined)\n lim = (1 << 29) - 1; // spec says 1 << 53, leaving it at 29 for constant folding\n else if (limit < 0)\n lim = 0;\n else\n lim = limit | 0;\n const s = S.length;\n let p = 0;\n const R = separator;\n if (lim == 0)\n return A;\n if (separator === undefined) {\n A[0] = S;\n return A;\n }\n if (s == 0) {\n let z = splitMatch(S, 0, R);\n if (z > -1) return A;\n A[0] = S;\n return A;\n }\n let T: string;\n let q = p;\n while (q != s) {\n let e = splitMatch(S, q, R);\n if (e < 0) q++;\n else {\n if (e == p) q++;\n else {\n T = stringSlice(S, p, q);\n A.push(T);\n if (A.length == lim) return A;\n p = e;\n q = p;\n }\n }\n }\n T = stringSlice(S, p, q);\n A.push(T);\n return A;\n }\n\n function splitMatch(S: string, q: number, R: string): number {\n const r = R.length;\n const s = S.length;\n if (q + r > s) return -1;\n for (let i = 0; i < r; ++i) {\n if (S[q + i] != R[i])\n return -1;\n }\n return q + r;\n }\n\n export function stringTrim(s: string): string {\n let start = 0;\n let end = s.length - 1;\n\n while (start <= end && isWhitespace(s.charCodeAt(start)))\n ++start;\n\n while (end > start && isWhitespace(s.charCodeAt(end)))\n --end;\n return s.slice(start, end + 1);\n }\n\n export function isWhitespace(c: number): boolean {\n // https://www.ecma-international.org/ecma-262/6.0/#sec-white-space\n switch (c) {\n case 0x0009: // character tab\n case 0x000B: // line tab\n case 0x000C: // form feed\n case 0x0020: // space\n case 0x00A0: // no-break space\n case 0xFEFF: // zero width no break space\n case 0x000A: // line feed\n case 0x000D: // carriage return\n case 0x2028: // line separator\n case 0x2029: // paragraph separator\n return true;\n default:\n return false;\n }\n }\n\n export function stringEmpty(S: string): boolean {\n return !S;\n }\n}\n\nnamespace Math {\n export function clamp(min: number, max: number, value: number): number {\n return Math.min(max, Math.max(min, value));\n }\n\n /**\n * Returns the absolute value of a number (the value without regard to whether it is positive or negative).\n * For example, the absolute value of -5 is the same as the absolute value of 5.\n * @param x A numeric expression for which the absolute value is needed.\n */\n //% blockId=math_op3\n //% help=math/abs\n export function abs(x: number): number {\n return x < 0 ? -x : x;\n }\n\n /**\n * Returns the sign of the x, indicating whether x is positive, negative or zero.\n * @param x The numeric expression to test\n */\n export function sign(x: number): number {\n if (x == 0) return 0;\n if (x > 0) return 1;\n return -1;\n }\n\n /**\n * Returns the larger of two supplied numeric expressions.\n */\n //% blockId=math_op2\n //% help=math/max\n export function max(a: number, b: number): number {\n if (a >= b) return a;\n return b;\n }\n\n /**\n * Returns the smaller of two supplied numeric expressions.\n */\n //% blockId=math_op2\n //% help=math/min\n export function min(a: number, b: number): number {\n if (a <= b) return a;\n return b;\n }\n\n /**\n * Rounds ``x`` to a number with the given number of ``digits``\n * @param x the number to round\n * @param digits the number of resulting digits\n */\n //%\n export function roundWithPrecision(x: number, digits: number): number {\n digits = digits | 0;\n // invalid digits input\n if (digits <= 0) return Math.round(x);\n if (x == 0) return 0;\n let r = 0;\n do {\n const d = Math.pow(10, digits);\n r = Math.round(x * d) / d;\n digits++;\n } while (r == 0 && digits < 21);\n return r;\n }\n}\n\n\n//% blockHidden=1\nnamespace __internal {\n /**\n * A shim to render a boolean as a down/up toggle\n */\n //% shim=TD_ID blockHidden=1\n //% blockId=toggleDownUp block=\"%down\"\n //% down.fieldEditor=toggledownup\n //% down.fieldOptions.decompileLiterals=true\n export function __downUp(down: boolean): boolean {\n return down;\n }\n\n /**\n * A shim to render a boolean as a up/down toggle\n */\n //% shim=TD_ID blockHidden=1\n //% blockId=toggleUpDown block=\"%up\"\n //% up.fieldEditor=toggleupdown\n //% up.fieldOptions.decompileLiterals=true\n export function __upDown(up: boolean): boolean {\n return up;\n }\n\n /**\n * A shim to render a boolean as a high/low toggle\n */\n //% shim=TD_ID blockHidden=1\n //% blockId=toggleHighLow block=\"%high\"\n //% high.fieldEditor=togglehighlow\n //% high.fieldOptions.decompileLiterals=true\n export function __highLow(high: boolean): boolean {\n return high;\n }\n\n /**\n * A shim to render a boolean as a on/off toggle\n */\n //% shim=TD_ID blockHidden=1\n //% blockId=toggleOnOff block=\"%on\"\n //% on.fieldEditor=toggleonoff\n //% on.fieldOptions.decompileLiterals=true\n export function __onOff(on: boolean): boolean {\n return on;\n }\n\n /**\n * A shim to render a boolean as a yes/no toggle\n */\n //% shim=TD_ID blockHidden=1\n //% blockId=toggleYesNo block=\"%yes\"\n //% yes.fieldEditor=toggleyesno\n //% yes.fieldOptions.decompileLiterals=true\n export function __yesNo(yes: boolean): boolean {\n return yes;\n }\n\n /**\n * A shim to render a boolean as a win/lose toggle\n */\n //% shim=TD_ID blockHidden=1\n //% blockId=toggleWinLose block=\"%win\"\n //% win.fieldEditor=togglewinlose\n //% win.fieldOptions.decompileLiterals=true\n export function __winLose(win: boolean): boolean {\n return win;\n }\n\n /**\n * Get the color wheel field editor\n * @param color color\n */\n //% blockId=colorNumberPicker block=\"%value\"\n //% blockHidden=true\n //% shim=TD_ID colorSecondary=\"#FFFFFF\"\n //% value.fieldEditor=\"colornumber\" value.fieldOptions.decompileLiterals=true\n //% value.defl='0xff0000'\n //% value.fieldOptions.colours='[\"#ff0000\",\"#ff8000\",\"#ffff00\",\"#ff9da5\",\"#00ff00\",\"#b09eff\",\"#00ffff\",\"#007fff\",\"#65471f\",\"#0000ff\",\"#7f00ff\",\"#ff0080\",\"#ff00ff\",\"#ffffff\",\"#999999\",\"#000000\"]'\n //% value.fieldOptions.columns=4 value.fieldOptions.className='rgbColorPicker'\n export function __colorNumberPicker(value: number) {\n return value;\n }\n\n /**\n * Get the color wheel field editor\n * @param value value between 0 to 255 to get a color value, eg: 10\n */\n //% blockId=colorWheelPicker block=\"%value\"\n //% blockHidden=true\n //% shim=TD_ID colorSecondary=\"#FFFFFF\"\n //% value.fieldEditor=\"colorwheel\" value.fieldOptions.decompileLiterals=true\n //% value.fieldOptions.sliderWidth='200'\n //% value.fieldOptions.min=0 value.fieldOptions.max=255\n export function __colorWheelPicker(value: number) {\n return value;\n }\n\n /**\n * Get the color wheel field editor using HSV values\n * @param value value between 0 to 255 to get a color value, eg: 10\n */\n //% blockId=colorWheelHsvPicker block=\"%value\"\n //% blockHidden=true\n //% shim=TD_ID colorSecondary=\"#FFFFFF\"\n //% value.fieldEditor=\"colorwheel\" value.fieldOptions.decompileLiterals=true\n //% value.fieldOptions.sliderWidth='200'\n //% value.fieldOptions.min=0 value.fieldOptions.max=255\n //% value.fieldOptions.channel=hsvfast\n export function __colorWheelHsvPicker(value: number) {\n return value;\n }\n\n /**\n * A speed picker\n * @param speed the speed, eg: 50\n */\n //% blockId=speedPicker block=\"%speed\" shim=TD_ID\n //% speed.fieldEditor=\"speed\" colorSecondary=\"#FFFFFF\"\n //% weight=0 blockHidden=1 speed.fieldOptions.decompileLiterals=1\n export function __speedPicker(speed: number): number {\n return speed;\n }\n\n /**\n * A turn ratio picker\n * @param turnratio the turn ratio, eg: 0\n */\n //% blockId=turnRatioPicker block=\"%turnratio\" shim=TD_ID\n //% turnratio.fieldEditor=\"turnratio\" colorSecondary=\"#FFFFFF\"\n //% weight=0 blockHidden=1 turnRatio.fieldOptions.decompileLiterals=1\n export function __turnRatioPicker(turnratio: number): number {\n return turnratio;\n }\n\n /**\n * A field editor that displays a protractor\n */\n //% blockId=protractorPicker block=\"%angle\"\n //% shim=TD_ID\n //% angle.fieldEditor=protractor\n //% angle.fieldOptions.decompileLiterals=1\n //% colorSecondary=\"#FFFFFF\"\n //% blockHidden=1\n export function __protractor(angle: number) {\n return angle;\n }\n\n /**\n * Get the time field editor\n * @param ms time duration in milliseconds, eg: 500, 1000\n */\n //% blockId=timePicker block=\"%ms\"\n //% blockHidden=true shim=TD_ID\n //% colorSecondary=\"#FFFFFF\"\n //% ms.fieldEditor=\"numberdropdown\" ms.fieldOptions.decompileLiterals=true\n //% ms.fieldOptions.data='[[\"100 ms\", 100], [\"200 ms\", 200], [\"500 ms\", 500], [\"1 second\", 1000], [\"2 seconds\", 2000], [\"5 seconds\", 5000]]'\n export function __timePicker(ms: number): number {\n return ms;\n }\n}\n",
1291
1291
  "pxt.cpp": "#include \"pxtbase.h\"\n\nusing namespace std;\n\nnamespace pxt {\n\nAction mkAction(int totallen, RefAction *act) {\n check(getVTable(act)->classNo == BuiltInType::RefAction, PANIC_INVALID_BINARY_HEADER, 1);\n#ifdef PXT_VM\n check(act->initialLen <= totallen, PANIC_INVALID_BINARY_HEADER, 13);\n#endif\n\n if (totallen == 0) {\n return (TValue)act; // no closure needed\n }\n\n void *ptr = gcAllocate(sizeof(RefAction) + totallen * sizeof(void *));\n RefAction *r = new (ptr) RefAction();\n r->len = totallen;\n#ifdef PXT_VM\n r->numArgs = act->numArgs;\n r->initialLen = act->initialLen;\n r->flags = 0;\n#endif\n r->func = act->func;\n memset(r->fields, 0, r->len * sizeof(void *));\n\n MEMDBG(\"mkAction: start=%p => %p\", act, r);\n\n return (Action)r;\n}\n\nRefRecord *mkClassInstance(VTable *vtable) {\n intcheck(vtable->methods[0] == &RefRecord_destroy, PANIC_SIZE, 3);\n // intcheck(vtable->methods[1] == &RefRecord_print, PANIC_SIZE, 4);\n\n void *ptr = gcAllocate(vtable->numbytes);\n RefRecord *r = new (ptr) RefRecord(vtable);\n memset(r->fields, 0, vtable->numbytes - sizeof(RefRecord));\n MEMDBG(\"mkClass: vt=%p => %p\", vtable, r);\n return r;\n}\n\nTValue RefRecord::ld(int idx) {\n // intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, PANIC_OUT_OF_BOUNDS, 1);\n return fields[idx];\n}\n\nTValue RefRecord::ldref(int idx) {\n // DMESG(\"LD %p len=%d reflen=%d idx=%d\", this, len, reflen, idx);\n // intcheck(0 <= idx && idx < reflen, PANIC_OUT_OF_BOUNDS, 2);\n return fields[idx];\n}\n\nvoid RefRecord::st(int idx, TValue v) {\n // intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, PANIC_OUT_OF_BOUNDS, 3);\n fields[idx] = v;\n}\n\nvoid RefRecord::stref(int idx, TValue v) {\n // DMESG(\"ST %p len=%d reflen=%d idx=%d\", this, len, reflen, idx);\n // intcheck(0 <= idx && idx < reflen, PANIC_OUT_OF_BOUNDS, 4);\n fields[idx] = v;\n}\n\nvoid RefObject::destroyVT() {\n ((RefObjectMethod)getVTable(this)->methods[0])(this);\n}\n\n//%\nvoid deleteRefObject(RefObject *obj) {\n obj->destroyVT();\n}\n\nvoid RefObject::printVT() {\n ((RefObjectMethod)getVTable(this)->methods[1])(this);\n}\n\nvoid RefRecord_destroy(RefRecord *) {}\n\nvoid RefRecord_print(RefRecord *r) {\n DMESG(\"RefRecord %p size=%d bytes\", r, getVTable(r)->numbytes);\n}\n\nvoid Segment::set(unsigned i, TValue value) {\n if (i < size) {\n data[i] = value;\n } else if (i < Segment::MaxSize) {\n growByMin(i + 1);\n data[i] = value;\n } else {\n return;\n }\n if (length <= i) {\n length = i + 1;\n }\n\n#ifdef DEBUG_BUILD\n DMESG(\"In Segment::set\");\n this->print();\n#endif\n\n return;\n}\n\nstatic inline int growthFactor(int size) {\n if (size == 0) {\n return 4;\n }\n if (size < 64) {\n return size * 2; // Double\n }\n if (size < 512) {\n return size * 5 / 3; // Grow by 1.66 rate\n }\n // Grow by constant rate\n if ((unsigned)size + 256 < Segment::MaxSize)\n return size + 256;\n else\n return Segment::MaxSize;\n}\n\nvoid LLSegment::setLength(unsigned newLen) {\n if (newLen > Segment::MaxSize)\n return;\n\n if (newLen > size) {\n int newSize = growthFactor(size);\n if (newSize < (int)newLen)\n newSize = newLen;\n\n // this will throw if unable to allocate\n TValue *tmp = (TValue *)(xmalloc(newSize * sizeof(TValue)));\n\n // Copy existing data\n if (size) {\n memcpy(tmp, data, size * sizeof(TValue));\n }\n // fill the rest with default value\n memset(tmp + size, 0, (newSize - size) * sizeof(TValue));\n\n // free older segment;\n xfree(data);\n\n data = tmp;\n size = newSize;\n } else if (newLen < length) {\n memset(data + newLen, 0, (length - newLen) * sizeof(TValue));\n }\n\n length = newLen;\n}\n\nvoid LLSegment::set(unsigned idx, TValue v) {\n if (idx >= Segment::MaxSize)\n return;\n if (idx >= length)\n setLength(idx + 1);\n data[idx] = v;\n}\n\nTValue LLSegment::pop() {\n if (length > 0) {\n --length;\n TValue value = data[length];\n data[length] = 0;\n return value;\n }\n return 0;\n}\n\nvoid LLSegment::destroy() {\n length = size = 0;\n xfree(data);\n data = nullptr;\n}\n\nvoid Segment::growByMin(ramint_t minSize) {\n ramint_t newSize = max(minSize, (ramint_t)growthFactor(size));\n\n if (size < newSize) {\n // this will throw if unable to allocate\n TValue *tmp = (TValue *)(gcAllocateArray(newSize * sizeof(TValue)));\n\n // Copy existing data\n if (size)\n memcpy(tmp, data, size * sizeof(TValue));\n // fill the rest with default value\n memset(tmp + size, 0, (newSize - size) * sizeof(TValue));\n\n data = tmp;\n size = newSize;\n\n#ifdef DEBUG_BUILD\n DMESG(\"growBy - after reallocation\");\n this->print();\n#endif\n }\n // else { no shrinking yet; }\n return;\n}\n\nvoid Segment::ensure(ramint_t newSize) {\n if (newSize < size) {\n return;\n }\n growByMin(newSize);\n}\n\nvoid Segment::setLength(unsigned newLength) {\n if (newLength > size) {\n ensure(newLength);\n }\n length = newLength;\n return;\n}\n\nTValue Segment::pop() {\n#ifdef DEBUG_BUILD\n DMESG(\"In Segment::pop\");\n this->print();\n#endif\n\n if (length > 0) {\n --length;\n TValue value = data[length];\n data[length] = Segment::DefaultValue;\n return value;\n }\n return Segment::DefaultValue;\n}\n\n// this function removes an element at index i and shifts the rest of the elements to\n// left to fill the gap\nTValue Segment::remove(unsigned i) {\n#ifdef DEBUG_BUILD\n DMESG(\"In Segment::remove index:%d\", i);\n this->print();\n#endif\n if (i < length) {\n // value to return\n TValue ret = data[i];\n if (i + 1 < length) {\n // Move the rest of the elements to fill in the gap.\n memmove(data + i, data + i + 1, (length - i - 1) * sizeof(void *));\n }\n length--;\n data[length] = Segment::DefaultValue;\n#ifdef DEBUG_BUILD\n DMESG(\"After Segment::remove index:%d\", i);\n this->print();\n#endif\n return ret;\n }\n return Segment::DefaultValue;\n}\n\n// this function inserts element value at index i by shifting the rest of the elements right.\nvoid Segment::insert(unsigned i, TValue value) {\n#ifdef DEBUG_BUILD\n DMESG(\"In Segment::insert index:%d value:%d\", i, value);\n this->print();\n#endif\n\n if (i < length) {\n ensure(length + 1);\n\n // Move the rest of the elements to fill in the gap.\n memmove(data + i + 1, data + i, (length - i) * sizeof(void *));\n\n data[i] = value;\n length++;\n } else {\n // This is insert beyond the length, just call set which will adjust the length\n set(i, value);\n }\n#ifdef DEBUG_BUILD\n DMESG(\"After Segment::insert index:%d\", i);\n this->print();\n#endif\n}\n\nvoid Segment::print() {\n DMESG(\"Segment: %p, length: %d, size: %d\", data, (unsigned)length, (unsigned)size);\n for (unsigned i = 0; i < size; i++) {\n DMESG(\"-> %d\", (unsigned)(uintptr_t)data[i]);\n }\n}\n\nvoid Segment::destroy() {\n#ifdef DEBUG_BUILD\n DMESG(\"In Segment::destroy\");\n this->print();\n#endif\n length = size = 0;\n data = nullptr;\n}\n\nPXT_VTABLE_CTOR(RefCollection) {}\n\nvoid RefCollection::destroy(RefCollection *t) {\n t->head.destroy();\n}\n\nvoid RefCollection::print(RefCollection *t) {\n DMESG(\"RefCollection %p size=%d\", t, t->head.getLength());\n t->head.print();\n}\n\nPXT_VTABLE(RefAction, ValType::Function)\nRefAction::RefAction() : PXT_VTABLE_INIT(RefAction) {}\n\n// fields[] contain captured locals\nvoid RefAction::destroy(RefAction *t) {}\n\nvoid RefAction::print(RefAction *t) {\n#ifdef PXT_VM\n DMESG(\"RefAction %p pc=%X size=%d\", t, (uint32_t)t->func, t->len);\n#else\n DMESG(\"RefAction %p pc=%X size=%d\", t, (const uint8_t *)t->func - (const uint8_t *)bytecode,\n t->len);\n#endif\n}\n\nPXT_VTABLE_CTOR(RefRefLocal) {\n v = 0;\n}\n\nvoid RefRefLocal::print(RefRefLocal *t) {\n DMESG(\"RefRefLocal %p v=%p\", t, (void *)t->v);\n}\n\nvoid RefRefLocal::destroy(RefRefLocal *t) {\n decr(t->v);\n}\n\nPXT_VTABLE_CTOR(RefMap) {}\n\nvoid RefMap::destroy(RefMap *t) {\n t->keys.destroy();\n t->values.destroy();\n}\n\nint RefMap::findIdx(String key) {\n auto len = keys.getLength();\n auto data = (String *)keys.getData();\n\n // fast path\n for (unsigned i = 0; i < len; ++i) {\n if (data[i] == key)\n return i;\n }\n\n // slow path\n auto keylen = key->getUTF8Size();\n auto keydata = key->getUTF8Data();\n for (unsigned i = 0; i < len; ++i) {\n auto s = data[i];\n if (s->getUTF8Size() == keylen && memcmp(keydata, s->getUTF8Data(), keylen) == 0)\n return i;\n }\n\n return -1;\n}\n\nvoid RefMap::print(RefMap *t) {\n DMESG(\"RefMap %p size=%d\", t, t->keys.getLength());\n}\n\nvoid debugMemLeaks() {}\n\nvoid error(PXT_PANIC code, int subcode) {\n DMESG(\"Error: %d [%d]\", code, subcode);\n target_panic(code);\n}\n\n#ifndef PXT_VM\nuint16_t *bytecode;\n#endif\nTValue *globals;\n\nvoid checkStr(bool cond, const char *msg) {\n if (!cond) {\n while (true) {\n // uBit.display.scroll(msg, 100);\n // uBit.sleep(100);\n }\n }\n}\n\n#ifdef PXT_VM\nint templateHash() {\n return *(int*)&vmImg->infoHeader->hexHash;\n}\n\nint programHash() {\n return *(int*)&vmImg->infoHeader->programHash;\n}\n\nint getNumGlobals() {\n return (int)vmImg->infoHeader->allocGlobals;\n}\n\nString programName() {\n return mkString((char *)vmImg->infoHeader->name);\n}\n#else\nint templateHash() {\n return ((int *)bytecode)[4];\n}\n\nint programHash() {\n return ((int *)bytecode)[6];\n}\n\nint getNumGlobals() {\n return bytecode[16];\n}\n\nString programName() {\n return ((String *)bytecode)[15];\n}\n#endif\n\n#ifndef PXT_VM\nvoid variantNotSupported(const char *v) {\n DMESG(\"variant not supported: %s\", v);\n target_panic(PANIC_VARIANT_NOT_SUPPORTED);\n}\n\nvoid exec_binary(unsigned *pc) {\n // XXX re-enable once the calibration code is fixed and [editor/embedded.ts]\n // properly prepends a call to [internal_main].\n // ::touch_develop::internal_main();\n\n // unique group for radio based on source hash\n // ::touch_develop::micro_bit::radioDefaultGroup = programHash();\n\n unsigned ver = *pc++;\n checkStr(ver == 0x4210, \":( Bad runtime version\");\n\n bytecode = *((uint16_t **)pc++); // the actual bytecode is here\n\n if (((uint32_t *)bytecode)[0] == 0x923B8E71) {\n variantNotSupported((const char *)bytecode + 16);\n return;\n }\n\n globals = (TValue *)app_alloc(sizeof(TValue) * getNumGlobals());\n memset(globals, 0, sizeof(TValue) * getNumGlobals());\n\n // can be any valid address, best in RAM for speed\n globals[0] = (TValue)&globals;\n\n // just compare the first word\n // TODO\n checkStr(((uint32_t *)bytecode)[0] == 0x923B8E70 && (unsigned)templateHash() == *pc,\n \":( Failed partial flash\");\n\n uintptr_t startptr = (uintptr_t)bytecode;\n\n startptr += 64; // header\n\n initPerfCounters();\n\n initRuntime();\n\n runAction0((Action)startptr);\n\n pxt::releaseFiber();\n}\n\nvoid start() {\n exec_binary((unsigned *)functionsAndBytecode);\n}\n#endif\n\n} // namespace pxt\n\nnamespace Array_ {\n//%\nbool isArray(TValue arr) {\n auto vt = getAnyVTable(arr);\n return vt && vt->classNo == BuiltInType::RefCollection;\n}\n} // namespace Array_\n\nnamespace pxtrt {\n//% expose\nRefCollection *keysOf(TValue v) {\n auto r = NEW_GC(RefCollection);\n MEMDBG(\"mkColl[keys]: => %p\", r);\n if (getAnyVTable(v) != &RefMap_vtable)\n return r;\n auto rm = (RefMap *)v;\n auto len = rm->keys.getLength();\n if (!len)\n return r;\n registerGCObj(r);\n r->setLength(len);\n auto dst = r->getData();\n memcpy(dst, rm->keys.getData(), len * sizeof(TValue));\n unregisterGCObj(r);\n return r;\n}\n//% expose\nTValue mapDeleteByString(RefMap *map, String key) {\n if (getAnyVTable((TValue)map) != &RefMap_vtable)\n soft_panic(PANIC_DELETE_ON_CLASS);\n int i = map->findIdx(key);\n if (i >= 0) {\n map->keys.remove(i);\n map->values.remove(i);\n }\n return TAG_TRUE;\n}\n\n} // namespace pxtrt\n",
1292
- "pxt.json": "{\n \"name\": \"base\",\n \"description\": \"The base library\",\n \"dependencies\": {},\n \"files\": [\n \"README.md\",\n \"pxt-core.d.ts\",\n \"pxt.cpp\",\n \"gc.cpp\",\n \"configkeys.h\",\n \"pxtbase.h\",\n \"core.cpp\",\n \"advmath.cpp\",\n \"trig.cpp\",\n \"pxt-helpers.ts\",\n \"fixed.ts\",\n \"buffer.cpp\",\n \"buffer.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"loops.cpp\",\n \"math.ts\",\n \"ns.ts\",\n \"control.cpp\",\n \"controlgc.cpp\",\n \"control.ts\",\n \"interval.ts\",\n \"gcstats.ts\",\n \"poll.ts\",\n \"console.ts\",\n \"json.ts\",\n \"templates.ts\",\n \"eventcontext.ts\",\n \"pause.ts\",\n \"forever.ts\",\n \"utfdecoder.ts\",\n \"scheduling.ts\",\n \"controlmessage.ts\",\n \"perfcounters.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"partial\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"PXT_GC_CHECKS\": 0\n },\n \"userConfigs\": [\n {\n \"description\": \"(Diagnostics) Garbage Collection checks.\",\n \"config\": {\n \"PXT_GC_CHECKS\": 1\n }\n }\n ]\n }\n}\n",
1292
+ "pxt.json": "{\n \"name\": \"base\",\n \"description\": \"The base library\",\n \"dependencies\": {},\n \"files\": [\n \"README.md\",\n \"pxt-core.d.ts\",\n \"pxt.cpp\",\n \"gc.cpp\",\n \"configkeys.h\",\n \"pxtbase.h\",\n \"core.cpp\",\n \"advmath.cpp\",\n \"trig.cpp\",\n \"pxt-helpers.ts\",\n \"fixed.ts\",\n \"buffer.cpp\",\n \"buffer.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"loops.cpp\",\n \"math.ts\",\n \"ns.ts\",\n \"control.cpp\",\n \"controlgc.cpp\",\n \"control.ts\",\n \"interval.ts\",\n \"gcstats.ts\",\n \"poll.ts\",\n \"console.ts\",\n \"json.ts\",\n \"templates.ts\",\n \"eventcontext.ts\",\n \"pause.ts\",\n \"forever.ts\",\n \"utfdecoder.ts\",\n \"scheduling.ts\",\n \"controlmessage.ts\",\n \"perfcounters.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"partial\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"PXT_GC_CHECKS\": 0\n },\n \"userConfigs\": [\n {\n \"description\": \"(Diagnostics) Garbage Collection checks.\",\n \"config\": {\n \"PXT_GC_CHECKS\": 1\n }\n }\n ]\n }\n}\n",
1293
1293
  "pxtbase.h": "#ifndef __PXTBASE_H\n#define __PXTBASE_H\n\n#pragma GCC diagnostic ignored \"-Wunused-parameter\"\n#pragma GCC diagnostic ignored \"-Wformat\"\n#pragma GCC diagnostic ignored \"-Warray-bounds\"\n\n// needed for gcc6; not sure why\n#undef min\n#undef max\n\n#define NOLOG(...) \\\n do { \\\n } while (0)\n\n#define MEMDBG NOLOG\n//#define MEMDBG DMESG\n#define MEMDBG2 NOLOG\n\n#include \"pxtconfig.h\"\n#include \"configkeys.h\"\n\n#ifndef PXT_UTF8\n#define PXT_UTF8 0\n#endif\n\n#if defined(PXT_VM)\n#include <stdint.h>\n#if UINTPTR_MAX == 0xffffffff\n#define PXT32 1\n#elif UINTPTR_MAX == 0xffffffffffffffff\n#define PXT64 1\n#else\n#error \"UINTPTR_MAX has invalid value\"\n#endif\n#endif\n\n#define intcheck(...) check(__VA_ARGS__)\n//#define intcheck(...) do {} while (0)\n\n#ifdef PXT_USE_FLOAT\n#define NUMBER float\n#else\n#define NUMBER double\n#endif\n\n#include <string.h>\n#include <stdint.h>\n#include <math.h>\n\n#ifdef POKY\nvoid *operator new(size_t size, void *ptr);\nvoid *operator new(size_t size);\n#else\n#include <new>\n#endif\n\n#include \"platform.h\"\n#include \"pxtcore.h\"\n\n#ifndef PXT_REGISTER_RESET\n#define PXT_REGISTER_RESET(fn) ((void)0)\n#endif\n\n#define PXT_REFCNT_FLASH 0xfffe\n\n#define CONCAT_1(a, b) a##b\n#define CONCAT_0(a, b) CONCAT_1(a, b)\n// already provided in some platforms, like mbedos\n#ifndef STATIC_ASSERT\n#define STATIC_ASSERT(e) enum { CONCAT_0(_static_assert_, __LINE__) = 1 / ((e) ? 1 : 0) };\n#endif\n\n#ifndef ramint_t\n// this type limits size of arrays\n#if defined(__linux__) || defined(PXT_VM)\n// TODO fix the inline array accesses to take note of this!\n#define ramint_t uint32_t\n#else\n#define ramint_t uint16_t\n#endif\n#endif\n\n#ifndef PXT_IN_ISR\n#define PXT_IN_ISR() (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)\n#endif\n\n#ifdef POKY\ninline void *operator new(size_t, void *p) {\n return p;\n}\ninline void *operator new[](size_t, void *p) {\n return p;\n}\n#endif\n\nnamespace pxt {\n\ntemplate <typename T> inline const T &max(const T &a, const T &b) {\n if (a < b)\n return b;\n return a;\n}\n\ntemplate <typename T> inline const T &min(const T &a, const T &b) {\n if (a < b)\n return a;\n return b;\n}\n\ntemplate <typename T> inline void swap(T &a, T &b) {\n T tmp = a;\n a = b;\n b = tmp;\n}\n\n//\n// Tagged values (assume 4 bytes for now, Cortex-M0)\n//\nstruct TValueStruct {};\ntypedef TValueStruct *TValue;\n\ntypedef TValue TNumber;\ntypedef TValue Action;\ntypedef TValue ImageLiteral;\n\n// To be implemented by the target\nextern \"C\" void target_panic(int error_code);\nextern \"C\" void target_reset();\nvoid sleep_ms(unsigned ms);\nvoid sleep_us(uint64_t us);\nvoid releaseFiber();\nuint64_t current_time_us();\nint current_time_ms();\nvoid initRuntime();\nvoid initSystemTimer();\nvoid sendSerial(const char *data, int len);\nvoid setSendToUART(void (*f)(const char *, int));\nuint64_t getLongSerialNumber();\nvoid registerWithDal(int id, int event, Action a, int flags = 16); // EVENT_LISTENER_DEFAULT_FLAGS\nvoid runInParallel(Action a);\nvoid runForever(Action a);\nvoid waitForEvent(int id, int event);\n//%\nunsigned afterProgramPage();\n//%\nvoid dumpDmesg();\nuint32_t hash_fnv1(const void *data, unsigned len);\n\n// also defined DMESG macro\n// end\n\n#define TAGGED_SPECIAL(n) (TValue)(void *)((n << 2) | 2)\n#define TAG_FALSE TAGGED_SPECIAL(2) // 10\n#define TAG_TRUE TAGGED_SPECIAL(16) // 66\n#define TAG_UNDEFINED (TValue)0\n#define TAG_NULL TAGGED_SPECIAL(1) // 6\n#define TAG_NAN TAGGED_SPECIAL(3) // 14\n#define TAG_NUMBER(n) (TNumber)(void *)(((uintptr_t)(uint32_t)(n) << 1) | 1)\n#define TAG_NON_VALUE TAGGED_SPECIAL(4) // 18; doesn't represent any JS value\n\n#ifdef PXT_VM\ninline bool isEncodedDouble(uint64_t v) {\n return (v >> 48) != 0;\n}\n#endif\n\ninline bool isDouble(TValue v) {\n#ifdef PXT64\n return ((uintptr_t)v >> 48) != 0;\n#else\n (void)v;\n return false;\n#endif\n}\n\ninline bool isPointer(TValue v) {\n return !isDouble(v) && v != 0 && ((intptr_t)v & 3) == 0;\n}\n\ninline bool isTagged(TValue v) {\n return (!isDouble(v) && ((intptr_t)v & 3)) || !v;\n}\n\ninline bool isInt(TValue v) {\n return !isDouble(v) && ((intptr_t)v & 1);\n}\n\ninline bool isSpecial(TValue v) {\n return !isDouble(v) && ((intptr_t)v & 2);\n}\n\ninline bool bothNumbers(TValue a, TValue b) {\n return !isDouble(a) && !isDouble(b) && ((intptr_t)a & (intptr_t)b & 1);\n}\n\ninline int numValue(TValue n) {\n return (int)((intptr_t)n >> 1);\n}\n\ninline bool canBeTagged(int v) {\n (void)v;\n#ifdef PXT_BOX_DEBUG\n return false;\n#elif defined(PXT64)\n return true;\n#else\n return (v << 1) >> 1 == v;\n#endif\n}\n\n// see https://anniecherkaev.com/the-secret-life-of-nan\n\n#define NanBoxingOffset 0x1000000000000LL\n\ntemplate <typename TO, typename FROM> TO bitwise_cast(FROM in) {\n STATIC_ASSERT(sizeof(TO) == sizeof(FROM));\n union {\n FROM from;\n TO to;\n } u;\n u.from = in;\n return u.to;\n}\n\ninline double decodeDouble(uint64_t v) {\n return bitwise_cast<double>(v - NanBoxingOffset);\n}\n\n#ifdef PXT64\nSTATIC_ASSERT(sizeof(void *) == 8);\ninline double doubleVal(TValue v) {\n return bitwise_cast<double>((uint64_t)v - NanBoxingOffset);\n}\n\ninline TValue tvalueFromDouble(double d) {\n return (TValue)(bitwise_cast<uint64_t>(d) + NanBoxingOffset);\n}\n#else\nSTATIC_ASSERT(sizeof(void *) == 4);\n#endif\n\n// keep in sym with sim/control.ts\ntypedef enum {\n PANIC_CODAL_OOM = 20,\n PANIC_GC_OOM = 21,\n PANIC_GC_TOO_BIG_ALLOCATION = 22,\n PANIC_CODAL_HEAP_ERROR = 30,\n PANIC_CODAL_NULL_DEREFERENCE = 40,\n PANIC_CODAL_USB_ERROR = 50,\n PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR = 90,\n\n PANIC_INVALID_BINARY_HEADER = 901,\n PANIC_OUT_OF_BOUNDS = 902,\n PANIC_REF_DELETED = 903,\n PANIC_SIZE = 904,\n PANIC_INVALID_VTABLE = 905,\n PANIC_INTERNAL_ERROR = 906,\n PANIC_NO_SUCH_CONFIG = 907,\n PANIC_NO_SUCH_PIN = 908,\n PANIC_INVALID_ARGUMENT = 909,\n PANIC_MEMORY_LIMIT_EXCEEDED = 910,\n PANIC_SCREEN_ERROR = 911,\n PANIC_MISSING_PROPERTY = 912,\n PANIC_INVALID_IMAGE = 913,\n PANIC_CALLED_FROM_ISR = 914,\n PANIC_HEAP_DUMPED = 915,\n PANIC_STACK_OVERFLOW = 916,\n PANIC_BLOCKING_TO_STRING = 917,\n PANIC_VM_ERROR = 918,\n PANIC_SETTINGS_CLEARED = 920,\n PANIC_SETTINGS_OVERLOAD = 921,\n PANIC_SETTINGS_SECRET_MISSING = 922,\n PANIC_DELETE_ON_CLASS = 923,\n PANIC_OUT_OF_TIMERS = 924,\n PANIC_JACDAC = 925,\n PANIC_MICROPHONE_MISSING = 926,\n PANIC_VARIANT_NOT_SUPPORTED = 927,\n\n PANIC_CAST_FIRST = 980,\n PANIC_CAST_FROM_UNDEFINED = 980,\n PANIC_CAST_FROM_BOOLEAN = 981,\n PANIC_CAST_FROM_NUMBER = 982,\n PANIC_CAST_FROM_STRING = 983,\n PANIC_CAST_FROM_OBJECT = 984,\n PANIC_CAST_FROM_FUNCTION = 985,\n PANIC_CAST_FROM_NULL = 989,\n\n PANIC_UNHANDLED_EXCEPTION = 999,\n\n} PXT_PANIC;\n\nextern const uintptr_t functionsAndBytecode[];\nextern TValue *globals;\nextern uint16_t *bytecode;\nclass RefRecord;\n\n// Utility functions\n\ntypedef TValue (*RunActionType)(Action a, TValue arg0, TValue arg1, TValue arg2);\n\n#define asmRunAction3 ((RunActionType)(((uintptr_t *)bytecode)[12]))\n\nstatic inline TValue runAction3(Action a, TValue arg0, TValue arg1, TValue arg2) {\n return asmRunAction3(a, arg0, arg1, 0);\n}\nstatic inline TValue runAction2(Action a, TValue arg0, TValue arg1) {\n return asmRunAction3(a, arg0, arg1, 0);\n}\nstatic inline TValue runAction1(Action a, TValue arg0) {\n return asmRunAction3(a, arg0, 0, 0);\n}\nstatic inline TValue runAction0(Action a) {\n return asmRunAction3(a, 0, 0, 0);\n}\n\nclass RefAction;\nclass BoxedString;\nstruct VTable;\n\n//%\nAction mkAction(int totallen, RefAction *act);\n//% expose\nint templateHash();\n//% expose\nint programHash();\n//% expose\nBoxedString *programName();\n//% expose\nunsigned programSize();\n//%\nint getNumGlobals();\n//%\nRefRecord *mkClassInstance(VTable *vt);\n//%\nvoid debugMemLeaks();\n//%\nvoid anyPrint(TValue v);\n\n//%\nint getConfig(int key, int defl = -1);\n\n//%\nint toInt(TNumber v);\n//%\nunsigned toUInt(TNumber v);\n//%\nNUMBER toDouble(TNumber v);\n//%\nfloat toFloat(TNumber v);\n//%\nTNumber fromDouble(NUMBER r);\n//%\nTNumber fromFloat(float r);\n\n//%\nTNumber fromInt(int v);\n//%\nTNumber fromUInt(unsigned v);\n//%\nTValue fromBool(bool v);\n//%\nbool eq_bool(TValue a, TValue b);\n//%\nbool eqq_bool(TValue a, TValue b);\n\n//%\nvoid failedCast(TValue v, void *addr = NULL);\n//%\nvoid missingProperty(TValue v);\n\nvoid error(PXT_PANIC code, int subcode = 0);\nvoid exec_binary(unsigned *pc);\nvoid start();\n\nstruct HandlerBinding {\n HandlerBinding *next;\n int source;\n int value;\n Action action;\n#ifndef PXT_CODAL\n uint32_t flags;\n struct Event *pending;\n#endif\n};\nHandlerBinding *findBinding(int source, int value);\nHandlerBinding *nextBinding(HandlerBinding *curr, int source, int value);\nvoid setBinding(int source, int value, Action act);\n\n// Legacy stuff; should no longer be used\n//%\nTValue incr(TValue e);\n//%\nvoid decr(TValue e);\n\ninline TValue incr(TValue e) {\n return e;\n}\ninline void decr(TValue e) {}\n\nclass RefObject;\n\nstatic inline RefObject *incrRC(RefObject *r) {\n return r;\n}\nstatic inline void decrRC(RefObject *) {}\n\ninline void *ptrOfLiteral(int offset) {\n return &bytecode[offset];\n}\n\n// Checks if object is ref-counted, and has a custom PXT vtable in front\n// TODO\ninline bool isRefCounted(TValue e) {\n return isPointer(e);\n}\n\ninline void check(int cond, PXT_PANIC code, int subcode = 0) {\n if (!cond)\n error(code, subcode);\n}\n\ninline void oops(int subcode = 0) {\n target_panic(800 + subcode);\n}\n\nclass RefObject;\n\ntypedef void (*RefObjectMethod)(RefObject *self);\ntypedef unsigned (*RefObjectSizeMethod)(RefObject *self);\ntypedef void *PVoid;\ntypedef void **PPVoid;\n\ntypedef void *Object_;\n\n#define VTABLE_MAGIC 0xF9\n#define VTABLE_MAGIC2 0xF8\n\nenum class ValType : uint8_t {\n Undefined,\n Boolean,\n Number,\n String,\n Object,\n Function,\n};\n\n// keep in sync with pxt-core (search for the type name)\nenum class BuiltInType : uint16_t {\n BoxedString = 1,\n BoxedNumber = 2,\n BoxedBuffer = 3,\n RefAction = 4,\n RefImage = 5,\n RefCollection = 6,\n RefRefLocal = 7,\n RefMap = 8,\n RefMImage = 9, // microbit-specific\n MMap = 10, // linux, mostly ev3\n BoxedString_SkipList = 11, // used by VM bytecode representation only\n BoxedString_ASCII = 12, // ditto\n ZPin = 13,\n User0 = 16,\n};\n\nstruct VTable {\n uint16_t numbytes;\n ValType objectType;\n uint8_t magic;\n#ifdef PXT_VM\n uint16_t ifaceHashEntries;\n BuiltInType lastClassNo;\n#else\n PVoid *ifaceTable;\n#endif\n BuiltInType classNo;\n uint16_t reserved;\n uint32_t ifaceHashMult;\n\n // we only use the first few methods here; pxt will generate more\n PVoid methods[8];\n};\n\n//%\nextern const VTable string_inline_ascii_vt;\n#if PXT_UTF8\n//%\nextern const VTable string_inline_utf8_vt;\n//%\nextern const VTable string_cons_vt;\n//%\nextern const VTable string_skiplist16_vt;\n//%\nextern const VTable string_skiplist16_packed_vt;\n#endif\n//%\nextern const VTable buffer_vt;\n//%\nextern const VTable number_vt;\n//%\nextern const VTable RefAction_vtable;\n\n#ifndef PXT_IS_READONLY\n// assume ARM - ram addresses are 0x2000_0000+; flash is either 0x0+ or 0x0800_0000+\n#define PXT_IS_READONLY(v) (isTagged(v) || !((uintptr_t)v >> 28))\n#endif\n\ninline bool isReadOnly(TValue v) {\n return PXT_IS_READONLY(v);\n}\n\n// A base abstract class for ref-counted objects.\nclass RefObject {\n public:\n const VTable *vtable;\n\n RefObject(const VTable *vt) {\n#if defined(PXT32) && defined(PXT_VM) && !defined(PXT_ESP32)\n if ((uint32_t)vt & 0xf0000000)\n target_panic(PANIC_INVALID_VTABLE);\n#endif\n vtable = vt;\n }\n\n void destroyVT();\n void printVT();\n\n inline uintptr_t vt() { return (uintptr_t)vtable; }\n inline void setVT(uintptr_t v) { vtable = (const VTable *)v; }\n\n inline void ref() {}\n inline void unref() {}\n inline bool isReadOnly() { return pxt::isReadOnly((TValue)this); }\n};\n\nclass Segment {\n private:\n TValue *data;\n ramint_t length;\n ramint_t size;\n\n // this just gives max value of ramint_t\n void growByMin(ramint_t minSize);\n void ensure(ramint_t newSize);\n\n public:\n static constexpr ramint_t MaxSize = (((1U << (8 * sizeof(ramint_t) - 1)) - 1) << 1) + 1;\n static constexpr TValue DefaultValue = TAG_UNDEFINED; // == NULL\n\n Segment() : data(nullptr), length(0), size(0) {}\n\n TValue get(unsigned i) { return i < length ? data[i] : NULL; }\n void set(unsigned i, TValue value);\n\n unsigned getLength() { return length; };\n void setLength(unsigned newLength);\n\n void push(TValue value) { set(length, value); }\n TValue pop();\n\n TValue remove(unsigned i);\n void insert(unsigned i, TValue value);\n\n void destroy();\n\n void print();\n\n TValue *getData() { return data; }\n};\n\n// Low-Level segment using system malloc\nclass LLSegment {\n private:\n TValue *data;\n ramint_t length;\n ramint_t size;\n\n public:\n LLSegment() : data(nullptr), length(0), size(0) {}\n\n void set(unsigned idx, TValue v);\n void push(TValue value) { set(length, value); }\n TValue pop();\n void destroy();\n void setLength(unsigned newLen);\n\n TValue get(unsigned i) { return i < length ? data[i] : NULL; }\n unsigned getLength() { return length; };\n TValue *getData() { return data; }\n};\n\n// A ref-counted collection of either primitive or ref-counted objects (String, Image,\n// user-defined record, another collection)\nclass RefCollection : public RefObject {\n public:\n Segment head;\n\n RefCollection();\n\n static void destroy(RefCollection *coll);\n static void scan(RefCollection *coll);\n static unsigned gcsize(RefCollection *coll);\n static void print(RefCollection *coll);\n\n unsigned length() { return head.getLength(); }\n void setLength(unsigned newLength) { head.setLength(newLength); }\n TValue getAt(int i) { return head.get(i); }\n TValue *getData() { return head.getData(); }\n};\n\nclass RefMap : public RefObject {\n public:\n Segment keys;\n Segment values;\n\n RefMap();\n static void destroy(RefMap *map);\n static void scan(RefMap *map);\n static unsigned gcsize(RefMap *coll);\n static void print(RefMap *map);\n int findIdx(BoxedString *key);\n};\n\n// A ref-counted, user-defined JS object.\nclass RefRecord : public RefObject {\n public:\n // The object is allocated, so that there is space at the end for the fields.\n TValue fields[];\n\n RefRecord(VTable *v) : RefObject(v) {}\n\n TValue ld(int idx);\n TValue ldref(int idx);\n void st(int idx, TValue v);\n void stref(int idx, TValue v);\n};\n\nstatic inline VTable *getVTable(RefObject *r) {\n return (VTable *)(r->vt() & ~1);\n}\n\nstatic inline VTable *getAnyVTable(TValue v) {\n if (!isRefCounted(v))\n return NULL;\n auto vt = getVTable((RefObject *)v);\n if (vt->magic == VTABLE_MAGIC)\n return vt;\n return NULL;\n}\n\n// these are needed when constructing vtables for user-defined classes\n//%\nvoid RefRecord_destroy(RefRecord *r);\n//%\nvoid RefRecord_print(RefRecord *r);\n//%\nvoid RefRecord_scan(RefRecord *r);\n//%\nunsigned RefRecord_gcsize(RefRecord *r);\n\ntypedef TValue (*ActionCB)(TValue *captured, TValue arg0, TValue arg1, TValue arg2);\n\n// Ref-counted function pointer.\nclass RefAction : public RefObject {\n public:\n uint16_t len;\n uint16_t numArgs;\n#ifdef PXT_VM\n uint16_t initialLen;\n uint16_t flags;\n uintptr_t func;\n#else\n ActionCB func; // The function pointer\n#endif\n // fields[] contain captured locals\n TValue fields[];\n\n static void destroy(RefAction *act);\n static void scan(RefAction *act);\n static unsigned gcsize(RefAction *coll);\n static void print(RefAction *act);\n\n RefAction();\n\n inline void stCore(int idx, TValue v) {\n // DMESG(\"ST [%d] = %d \", idx, v); this->print();\n intcheck(0 <= idx && idx < len, PANIC_OUT_OF_BOUNDS, 10);\n intcheck(fields[idx] == 0, PANIC_OUT_OF_BOUNDS, 11); // only one assignment permitted\n fields[idx] = v;\n }\n};\n\n// These two are used to represent locals written from inside inline functions\nclass RefRefLocal : public RefObject {\n public:\n TValue v;\n static void destroy(RefRefLocal *l);\n static void scan(RefRefLocal *l);\n static unsigned gcsize(RefRefLocal *l);\n static void print(RefRefLocal *l);\n RefRefLocal();\n};\n\ntypedef int color;\n\n// note: this is hardcoded in PXT (hexfile.ts)\n\nclass BoxedNumber : public RefObject {\n public:\n NUMBER num;\n BoxedNumber() : RefObject(&number_vt) {}\n} __attribute__((packed));\n\nclass BoxedString : public RefObject {\n public:\n union {\n struct {\n uint16_t length; // ==size\n char data[0];\n } ascii;\n#if PXT_UTF8\n struct {\n uint16_t size;\n char data[0];\n } utf8;\n struct {\n BoxedString *left;\n BoxedString *right;\n } cons;\n struct {\n uint16_t size; // in bytes\n uint16_t length; // in characters\n uint16_t *list;\n } skip;\n struct {\n uint16_t size; // in bytes\n uint16_t length; // in characters\n uint16_t list[0];\n } skip_pack;\n#endif\n };\n\n#if PXT_UTF8\n uintptr_t runMethod(int idx) {\n return ((uintptr_t(*)(BoxedString *))vtable->methods[idx])(this);\n }\n const char *getUTF8Data() { return (const char *)runMethod(4); }\n uint32_t getUTF8Size() { return (uint32_t)runMethod(5); }\n // in characters\n uint32_t getLength() { return (uint32_t)runMethod(6); }\n const char *getUTF8DataAt(uint32_t pos) {\n auto meth = ((const char *(*)(BoxedString *, uint32_t))vtable->methods[7]);\n return meth(this, pos);\n }\n#else\n const char *getUTF8Data() { return ascii.data; }\n uint32_t getUTF8Size() { return ascii.length; }\n uint32_t getLength() { return ascii.length; }\n const char *getUTF8DataAt(uint32_t pos) { return pos < ascii.length ? ascii.data + pos : NULL; }\n#endif\n\n TNumber charCodeAt(int pos);\n\n BoxedString(const VTable *vt) : RefObject(vt) {}\n};\n\n// cross version compatible way of accessing string data\n#ifndef PXT_STRING_DATA\n#define PXT_STRING_DATA(str) str->getUTF8Data()\n#endif\n\n// cross version compatible way of accessing string length\n#ifndef PXT_STRING_DATA_LENGTH\n#define PXT_STRING_DATA_LENGTH(str) str->getUTF8Size()\n#endif\n\nclass BoxedBuffer : public RefObject {\n public:\n // data needs to be word-aligned, so we use 32 bits for length\n int length;\n uint8_t data[0];\n BoxedBuffer() : RefObject(&buffer_vt) {}\n\n static bool isInstance(TValue v);\n};\n\n// cross version compatible way of access data field\n#ifndef PXT_BUFFER_DATA\n#define PXT_BUFFER_DATA(buffer) buffer->data\n#endif\n\n// cross version compatible way of access data length\n#ifndef PXT_BUFFER_LENGTH\n#define PXT_BUFFER_LENGTH(buffer) buffer->length\n#endif\n\n#ifndef PXT_CREATE_BUFFER\n#define PXT_CREATE_BUFFER(data, len) pxt::mkBuffer(data, len)\n#endif\n\n// Legacy format:\n// the first byte of data indicates the format - currently 0xE1 or 0xE4 to 1 or 4 bit bitmaps\n// second byte indicates width in pixels\n// third byte indicates the height (which should also match the size of the buffer)\n// just like ordinary buffers, these can be layed out in flash\n\n// Current format:\n// 87 BB WW WW HH HH 00 00 DATA\n// that is: 0x87, 0x01 or 0x04 - bpp, width in little endian, height, 0x00, 0x00 followed by data\n// for 4 bpp images, rows are word-aligned (as in legacy)\n\n#define IMAGE_HEADER_MAGIC 0x87\n\nstruct ImageHeader {\n uint8_t magic;\n uint8_t bpp;\n uint16_t width;\n uint16_t height;\n uint16_t padding;\n uint8_t pixels[0];\n};\n\nclass RefImage : public RefObject {\n public:\n BoxedBuffer *buffer;\n uint32_t revision;\n\n RefImage(BoxedBuffer *buf);\n RefImage(uint32_t sz);\n\n void setBuffer(BoxedBuffer *b);\n\n uint8_t *data() { return buffer->data; }\n int length() { return (int)buffer->length; }\n\n ImageHeader *header() { return (ImageHeader *)buffer->data; }\n int pixLength() { return length() - sizeof(ImageHeader); }\n\n int width() { return header()->width; }\n int height() { return header()->height; }\n int wordHeight();\n int bpp() { return header()->bpp; }\n\n bool hasPadding() { return (height() & 0x7) != 0; }\n\n uint8_t *pix() { return header()->pixels; }\n\n int byteHeight() {\n if (bpp() == 1)\n return (height() + 7) >> 3;\n else if (bpp() == 4)\n return ((height() * 4 + 31) >> 5) << 2;\n else {\n oops(21);\n return -1;\n }\n }\n\n uint8_t *pix(int x, int y) {\n uint8_t *d = &pix()[byteHeight() * x];\n if (y) {\n if (bpp() == 1)\n d += y >> 3;\n else if (bpp() == 4)\n d += y >> 1;\n }\n return d;\n }\n\n uint8_t fillMask(color c);\n bool inRange(int x, int y);\n void clamp(int *x, int *y);\n void makeWritable();\n\n static void destroy(RefImage *t);\n static void scan(RefImage *t);\n static unsigned gcsize(RefImage *t);\n static void print(RefImage *t);\n};\n\nRefImage *mkImage(int w, int h, int bpp);\n\ntypedef BoxedBuffer *Buffer;\ntypedef BoxedString *String;\ntypedef RefImage *Image_;\n\nuint32_t toRealUTF8(String str, uint8_t *dst);\n\n// keep in sync with github/pxt/pxtsim/libgeneric.ts\nenum class NumberFormat {\n Int8LE = 1,\n UInt8LE,\n Int16LE,\n UInt16LE,\n Int32LE,\n Int8BE,\n UInt8BE,\n Int16BE,\n UInt16BE,\n Int32BE,\n\n UInt32LE,\n UInt32BE,\n Float32LE,\n Float64LE,\n Float32BE,\n Float64BE,\n};\n\n// this will, unlike mkStringCore, UTF8-canonicalize the data\nString mkString(const char *data, int len = -1);\n// data can be NULL in both cases\nBuffer mkBuffer(const void *data, int len);\nString mkStringCore(const char *data, int len = -1);\n\nTNumber getNumberCore(uint8_t *buf, int size, NumberFormat format);\nvoid setNumberCore(uint8_t *buf, int size, NumberFormat format, TNumber value);\n\nvoid seedRandom(unsigned seed);\nvoid seedAddRandom(unsigned seed);\n// max is inclusive\nunsigned getRandom(unsigned max);\n\nValType valType(TValue v);\n\n// this is equivalent to JS `throw v`; it will leave\n// the current function(s), all the way until the nearest try block and\n// ignore all destructors (think longjmp())\nvoid throwValue(TValue v);\n\nvoid registerGC(TValue *root, int numwords = 1);\nvoid unregisterGC(TValue *root, int numwords = 1);\nvoid registerGCPtr(TValue ptr);\nvoid unregisterGCPtr(TValue ptr);\nstatic inline void registerGCObj(RefObject *ptr) {\n registerGCPtr((TValue)ptr);\n}\nstatic inline void unregisterGCObj(RefObject *ptr) {\n unregisterGCPtr((TValue)ptr);\n}\nvoid gc(int flags);\n\nstruct StackSegment {\n void *top;\n void *bottom;\n StackSegment *next;\n};\n\n#define NUM_TRY_FRAME_REGS 3\nstruct TryFrame {\n TryFrame *parent;\n uintptr_t registers[NUM_TRY_FRAME_REGS];\n};\n\nstruct ThreadContext {\n TValue *globals;\n StackSegment stack;\n TryFrame *tryFrame;\n TValue thrownValue;\n#ifdef PXT_GC_THREAD_LIST\n ThreadContext *next;\n ThreadContext *prev;\n#endif\n};\n\n#ifdef PXT_GC_THREAD_LIST\nextern ThreadContext *threadContexts;\nvoid *threadAddressFor(ThreadContext *, void *sp);\n#endif\n\nvoid releaseThreadContext(ThreadContext *ctx);\nThreadContext *getThreadContext();\nvoid setThreadContext(ThreadContext *ctx);\n\n#ifndef PXT_GC_THREAD_LIST\nvoid gcProcessStacks(int flags);\n#endif\n\nvoid gcProcess(TValue v);\nvoid gcFreeze();\n\n#ifdef PXT_VM\nvoid gcStartup();\nvoid gcPreStartup();\n#endif\n\nvoid coreReset();\nvoid gcReset();\nvoid systemReset();\n\nvoid doNothing();\n\nvoid *gcAllocate(int numbytes);\nvoid *gcAllocateArray(int numbytes);\nextern \"C\" void *app_alloc(int numbytes);\nextern \"C\" void *app_free(void *ptr);\nextern \"C\" void *app_alloc_at(void *at, int numbytes);\nvoid gcPreAllocateBlock(uint32_t sz);\n\nint redirectSamples(int16_t *dst, int numsamples, int samplerate);\n\n#ifdef PXT64\n#define TOWORDS(bytes) (((bytes) + 7) >> 3)\n#else\n#define TOWORDS(bytes) (((bytes) + 3) >> 2)\n#endif\n\n#ifndef PXT_VM\n#define soft_panic target_panic\n#endif\n\nextern int debugFlags;\n\nenum class PerfCounters {\n GC,\n};\n\n#ifdef PXT_PROFILE\n#ifndef PERF_NOW\n#error \"missing platform timer support\"\n#endif\n\n#ifndef PERF_NOW_MASK\n#define PERF_NOW_MASK 0xffffffff\n#endif\n\n#ifndef PERF_NOW_SCALE\n#define PERF_NOW_SCALE 1\n#endif\n\nstruct PerfCounter {\n uint32_t value;\n uint32_t numstops;\n uint32_t start;\n};\n\nextern struct PerfCounter *perfCounters;\n\nvoid initPerfCounters();\n//%\nvoid dumpPerfCounters();\n//%\nvoid startPerfCounter(PerfCounters n);\n//%\nvoid stopPerfCounter(PerfCounters n);\n#else\ninline void startPerfCounter(PerfCounters n) {}\ninline void stopPerfCounter(PerfCounters n) {}\ninline void initPerfCounters() {}\ninline void dumpPerfCounters() {}\n#endif\n\n// Handling of built-in string literals (like \"[Object]\", \"true\" etc.).\n\n// This has the same layout as BoxedString, but has statically allocated buffer\ntemplate <size_t N> struct BoxedStringLayout {\n const void *vtable;\n uint16_t size;\n const char data[N];\n};\n\ntemplate <size_t N> constexpr size_t _boxedStringLen(char const (&)[N]) {\n return N;\n}\n\n// strings defined here as used as (String)name\n#define PXT_DEF_STRING(name, val) \\\n const BoxedStringLayout<_boxedStringLen(val)> name[1] = { \\\n {&pxt::string_inline_ascii_vt, _boxedStringLen(val) - 1, val}};\n\n// bigger value - less memory, but slower\n// 16/20 keeps s.length and s.charCodeAt(i) at about 200 cycles (for actual unicode strings),\n// which is similar to amortized allocation time\n#define PXT_STRING_SKIP_INCR 16 // needs to be power of 2; needs to be kept in sync with compiler\n#define PXT_STRING_MIN_SKIP \\\n 20 // min. size of string to use skip list; static code has its own limit\n\n#define PXT_NUM_SKIP_ENTRIES(p) ((p)->skip.length / PXT_STRING_SKIP_INCR)\n#define PXT_SKIP_DATA_IND(p) ((const char *)(p->skip.list + PXT_NUM_SKIP_ENTRIES(p)))\n#define PXT_SKIP_DATA_PACK(p) ((const char *)(p->skip_pack.list + PXT_NUM_SKIP_ENTRIES(p)))\n\n} // namespace pxt\n\nusing namespace pxt;\n\nnamespace numops {\n//%\nString toString(TValue v);\n//%\nint toBool(TValue v);\n//%\nint toBoolDecr(TValue v);\n} // namespace numops\n\nnamespace pxt {\ninline bool toBoolQuick(TValue v) {\n if (v == TAG_TRUE)\n return true;\n if (v == TAG_FALSE || v == TAG_UNDEFINED || v == TAG_NULL)\n return false;\n return numops::toBool(v);\n}\n} // namespace pxt\n\nnamespace pxtrt {\n//%\nRefMap *mkMap();\n//%\nTValue mapGetByString(RefMap *map, String key);\n//%\nint lookupMapKey(String key);\n//%\nTValue mapGet(RefMap *map, unsigned key);\n//% expose\nvoid mapSetByString(RefMap *map, String key, TValue val);\n//%\nvoid mapSet(RefMap *map, unsigned key, TValue val);\n} // namespace pxtrt\n\nnamespace pins {\nBuffer createBuffer(int size);\n}\n\nnamespace String_ {\n//%\nint compare(String a, String b);\n} // namespace String_\n\nnamespace Array_ {\n//%\nRefCollection *mk();\n//%\nint length(RefCollection *c);\n//%\nvoid setLength(RefCollection *c, int newLength);\n//%\nvoid push(RefCollection *c, TValue x);\n//%\nTValue pop(RefCollection *c);\n//%\nTValue getAt(RefCollection *c, int x);\n//%\nvoid setAt(RefCollection *c, int x, TValue y);\n//%\nTValue removeAt(RefCollection *c, int x);\n//%\nvoid insertAt(RefCollection *c, int x, TValue value);\n//%\nint indexOf(RefCollection *c, TValue x, int start);\n//%\nbool removeElement(RefCollection *c, TValue x);\n} // namespace Array_\n\n#define NEW_GC(T, ...) new (gcAllocate(sizeof(T))) T(__VA_ARGS__)\n\n// The ARM Thumb generator in the JavaScript code is parsing\n// the hex file and looks for the magic numbers as present here.\n//\n// Then it fetches function pointer addresses from there.\n//\n// The vtable pointers are there, so that the ::emptyData for various types\n// can be patched with the right vtable.\n//\n#define PXT_SHIMS_BEGIN \\\n namespace pxt { \\\n const uintptr_t functionsAndBytecode[] \\\n __attribute__((aligned(0x20))) = {0x08010801, 0x42424242, 0x08010801, 0x8de9d83e,\n\n#define PXT_SHIMS_END \\\n } \\\n ; \\\n }\n\n#if !defined(X86_64) && !defined(PXT_VM)\n#pragma GCC diagnostic ignored \"-Wpmf-conversions\"\n#endif\n\n#ifdef PXT_VM\n#define DEF_VTABLE(name, tp, valtype, ...) \\\n const VTable name = {sizeof(tp), valtype, VTABLE_MAGIC, 0, BuiltInType::tp, BuiltInType::tp, \\\n 0, 0, {__VA_ARGS__}};\n#define DEF_VTABLE_EXT(name, tp, valtype, ...) \\\n const VTable name = {sizeof(tp), valtype, VTABLE_MAGIC2, 0, BuiltInType::tp, BuiltInType::tp, \\\n 0, 0, {__VA_ARGS__}};\n#else\n#define DEF_VTABLE(name, tp, valtype, ...) \\\n const VTable name = {sizeof(tp), valtype, VTABLE_MAGIC, 0, BuiltInType::tp, \\\n 0, 0, {__VA_ARGS__}};\n#define DEF_VTABLE_EXT(name, tp, valtype, ...) \\\n const VTable name = {sizeof(tp), valtype, VTABLE_MAGIC2, 0, BuiltInType::tp, \\\n 0, 0, {__VA_ARGS__}};\n#endif\n\n#define PXT_VTABLE(classname, valtp) \\\n DEF_VTABLE(classname##_vtable, classname, valtp, (void *)&classname::destroy, \\\n (void *)&classname::print, (void *)&classname::scan, (void *)&classname::gcsize)\n\n#define PXT_EXT_VTABLE(classname) \\\n static int classname##_gcsize() { return sizeof(classname); } \\\n DEF_VTABLE_EXT(classname##_vtable, classname, ValType::Object, (void *)&pxt::doNothing, \\\n (void *)&pxt::anyPrint, (void *)&pxt::doNothing, (void *)&classname##_gcsize)\n\n#define PXT_VTABLE_INIT(classname) RefObject(&classname##_vtable)\n\n#define PXT_VTABLE_CTOR(classname) \\\n PXT_VTABLE(classname, ValType::Object) \\\n classname::classname() : PXT_VTABLE_INIT(classname)\n\n#define PXT_MAIN \\\n int main() { \\\n pxt::start(); \\\n return 0; \\\n }\n\n#define PXT_FNPTR(x) (uintptr_t)(void *)(x)\n\n#define PXT_ABI(...)\n\n#define JOIN(a, b) a##b\n/// Defines getClassName() function to fetch the singleton\n#define SINGLETON(ClassName) \\\n static ClassName *JOIN(inst, ClassName); \\\n ClassName *JOIN(get, ClassName)() { \\\n if (!JOIN(inst, ClassName)) \\\n JOIN(inst, ClassName) = new ClassName(); \\\n return JOIN(inst, ClassName); \\\n }\n\n/// Defines getClassName() function to fetch the singleton if PIN present\n#define SINGLETON_IF_PIN(ClassName, pin) \\\n static ClassName *JOIN(inst, ClassName); \\\n ClassName *JOIN(get, ClassName)() { \\\n if (!JOIN(inst, ClassName) && LOOKUP_PIN(pin)) \\\n JOIN(inst, ClassName) = new ClassName(); \\\n return JOIN(inst, ClassName); \\\n }\n\n#ifdef PXT_VM\n#include \"vm.h\"\n#endif\n\n#endif\n",
1294
1294
  "scheduling.ts": "/**\n * Calls a function with a fixed time delay between each call to that function.\n * @param func \n * @param delay \n */\n//%\nfunction setInterval(func: () => void, delay: number): number {\n delay = Math.max(10, delay | 0);\n return control.setInterval(func, delay, control.IntervalMode.Interval);\n}\n\n/**\n * Cancels repeated action which was set up using setInterval().\n * @param intervalId \n */\n//%\nfunction clearInterval(intervalId: number) {\n control.clearInterval(intervalId, control.IntervalMode.Interval);\n}\n\n/**\n * Calls a function after specified delay.\n * @param func \n * @param delay \n */\n//%\nfunction setTimeout(func: () => void, delay: number): number {\n return control.setInterval(func, delay, control.IntervalMode.Timeout);\n}\n\n/**\n * Clears the delay set by setTimeout().\n * @param intervalId \n */\n//%\nfunction clearTimeout(intervalId: number) {\n control.clearInterval(intervalId, control.IntervalMode.Timeout);\n}\n\n/**\n * Calls a function as soon as possible.\n * @param func \n */\n//%\nfunction setImmediate(func: () => void): number {\n return control.setInterval(func, 0, control.IntervalMode.Immediate);\n}\n\n/**\n * Cancels the immediate actions.\n * @param intervalId \n */\n//%\nfunction clearImmediate(intervalId: number) {\n control.clearInterval(intervalId, control.IntervalMode.Immediate);\n}\n",
1295
1295
  "shims.d.ts": "// Auto-generated. Do not edit.\n\n\n\n //% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte\ndeclare interface Buffer {\n /**\n * Reads an unsigned byte at a particular location\n */\n //% shim=BufferMethods::getUint8\n getUint8(off: int32): int32;\n\n /**\n * Returns false when the buffer can be written to.\n */\n //% shim=BufferMethods::isReadOnly\n isReadOnly(): boolean;\n\n /**\n * Writes an unsigned byte at a particular location\n */\n //% shim=BufferMethods::setUint8\n setUint8(off: int32, v: int32): void;\n\n /**\n * Write a number in specified format in the buffer.\n */\n //% shim=BufferMethods::setNumber\n setNumber(format: NumberFormat, offset: int32, value: number): void;\n\n /**\n * Read a number in specified format from the buffer.\n */\n //% shim=BufferMethods::getNumber\n getNumber(format: NumberFormat, offset: int32): number;\n\n /** Returns the length of a Buffer object. */\n //% property shim=BufferMethods::length\n length: int32;\n\n /**\n * Fill (a fragment) of the buffer with given value.\n */\n //% offset.defl=0 length.defl=-1 shim=BufferMethods::fill\n fill(value: int32, offset?: int32, length?: int32): void;\n\n /**\n * Return a copy of a fragment of a buffer.\n */\n //% offset.defl=0 length.defl=-1 shim=BufferMethods::slice\n slice(offset?: int32, length?: int32): Buffer;\n\n /**\n * Shift buffer left in place, with zero padding.\n * @param offset number of bytes to shift; use negative value to shift right\n * @param start start offset in buffer. Default is 0.\n * @param length number of elements in buffer. If negative, length is set as the buffer length minus\n * start. eg: -1\n */\n //% start.defl=0 length.defl=-1 shim=BufferMethods::shift\n shift(offset: int32, start?: int32, length?: int32): void;\n\n /**\n * Convert a buffer to string assuming UTF8 encoding\n */\n //% shim=BufferMethods::toString\n toString(): string;\n\n /**\n * Convert a buffer to its hexadecimal representation.\n */\n //% shim=BufferMethods::toHex\n toHex(): string;\n\n /**\n * Rotate buffer left in place.\n * @param offset number of bytes to shift; use negative value to shift right\n * @param start start offset in buffer. Default is 0.\n * @param length number of elements in buffer. If negative, length is set as the buffer length minus\n * start. eg: -1\n */\n //% start.defl=0 length.defl=-1 shim=BufferMethods::rotate\n rotate(offset: int32, start?: int32, length?: int32): void;\n\n /**\n * Write contents of `src` at `dstOffset` in current buffer.\n */\n //% shim=BufferMethods::write\n write(dstOffset: int32, src: Buffer): void;\n\n /**\n * Compute k-bit FNV-1 non-cryptographic hash of the buffer.\n */\n //% shim=BufferMethods::hash\n hash(bits: int32): uint32;\n}\ndeclare namespace control {\n\n /**\n * Create a new zero-initialized buffer.\n * @param size number of bytes in the buffer\n */\n //% deprecated=1 shim=control::createBuffer\n function createBuffer(size: int32): Buffer;\n\n /**\n * Create a new buffer with UTF8-encoded string\n * @param str the string to put in the buffer\n */\n //% deprecated=1 shim=control::createBufferFromUTF8\n function createBufferFromUTF8(str: string): Buffer;\n}\ndeclare namespace loops {\n\n /**\n * Repeats the code forever in the background. On each iteration, allows other codes to run.\n * @param body code to execute\n */\n //% help=loops/forever weight=100 afterOnStart=true deprecated=true\n //% blockId=forever_deprecated block=\"forever\" blockAllowMultiple=1 shim=loops::forever\n function forever(a: () => void): void;\n\n /**\n * Pause for the specified time in milliseconds\n * @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000\n */\n //% help=loops/pause weight=99 deprecated=true\n //% async block=\"pause %pause=timePicker|ms\"\n //% blockId=device_pause_deprecated shim=loops::pause\n function pause(ms: int32): void;\n}\ndeclare namespace control {\n\n /**\n * Gets the number of milliseconds elapsed since power on.\n */\n //% help=control/millis weight=50\n //% blockId=control_running_time block=\"millis (ms)\" shim=control::millis\n function millis(): int32;\n\n /**\n * Gets current time in microseconds. Overflows every ~18 minutes.\n */\n //% shim=control::micros\n function micros(): int32;\n\n /**\n * Used internally\n */\n //% flags.defl=16 shim=control::internalOnEvent\n function internalOnEvent(src: int32, value: int32, handler: () => void, flags?: int32): void;\n\n /**\n * Reset the device.\n */\n //% weight=30 async help=control/reset blockGap=8\n //% blockId=\"control_reset\" block=\"reset\" shim=control::reset\n function reset(): void;\n\n /**\n * Block the current fiber for the given microseconds\n * @param micros number of micro-seconds to wait. eg: 4\n */\n //% help=control/wait-micros weight=29 async\n //% blockId=\"control_wait_us\" block=\"wait (µs)%micros\" shim=control::waitMicros\n function waitMicros(micros: int32): void;\n\n /**\n * Run other code in the parallel.\n */\n //% help=control/run-in-parallel handlerStatement=1\n //% blockId=\"control_run_in_parallel\" block=\"run in parallel\" blockGap=8 shim=control::runInParallel\n function runInParallel(a: () => void): void;\n\n /**\n * Blocks the calling thread until the specified event is raised.\n */\n //% help=control/wait-for-event async\n //% blockId=control_wait_for_event block=\"wait for event|from %src|with value %value\" shim=control::waitForEvent\n function waitForEvent(src: int32, value: int32): void;\n\n /**\n * Derive a unique, consistent serial number of this device from internal data.\n */\n //% blockId=\"control_device_serial_number\" block=\"device serial number\" weight=9\n //% help=control/device-serial-number shim=control::deviceSerialNumber\n function deviceSerialNumber(): int32;\n\n /**\n * Derive a unique, consistent 64-bit serial number of this device from internal data.\n */\n //% blockId=\"control_device_long_serial_number\" block=\"device long serial number\" weight=9\n //% help=control/device-long-serial-number shim=control::deviceLongSerialNumber\n function deviceLongSerialNumber(): Buffer;\n\n /**\n *\n */\n //% shim=control::__log\n function __log(prority: int32, text: string): void;\n\n /**\n * Dump internal information about a value.\n */\n //% shim=control::dmesgValue\n function dmesgValue(v: any): void;\n}\ndeclare namespace control {\n\n /**\n * Force GC and dump basic information about heap.\n */\n //% shim=control::gc\n function gc(): void;\n\n /**\n * Force GC and halt waiting for debugger to do a full heap dump.\n */\n //% shim=control::heapDump\n function heapDump(): void;\n\n /**\n * Set flags used when connecting an external debugger.\n */\n //% shim=control::setDebugFlags\n function setDebugFlags(flags: int32): void;\n\n /**\n * Record a heap snapshot to debug memory leaks.\n */\n //% shim=control::heapSnapshot\n function heapSnapshot(): void;\n\n /**\n * Return true if profiling is enabled in the current build.\n */\n //% shim=control::profilingEnabled\n function profilingEnabled(): boolean;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1302,7 +1302,7 @@ var pxtTargetBundle = {
1302
1302
  "README.md": "# buttons\n\nA library to handle 2 buttons A and B.\n",
1303
1303
  "buttons.cpp": "#include \"pxt.h\"\n\n/*\n\nThese button events need CODAL work.\n\n // % block=\"double click\"\n DoubleClick = DEVICE_BUTTON_EVT_DOUBLE_CLICK,\n\n // % block=\"hold\"\n Hold = DEVICE_BUTTON_EVT_HOLD\n\n*/\n\n/**\n * User interaction on buttons\n */\nenum class ButtonEvent {\n //% block=\"click\"\n Click = DEVICE_BUTTON_EVT_CLICK,\n //% block=\"long click\"\n LongClick = DEVICE_BUTTON_EVT_LONG_CLICK,\n //% block=\"up\"\n Up = DEVICE_BUTTON_EVT_UP,\n //% block=\"down\"\n Down = DEVICE_BUTTON_EVT_DOWN\n};\n\nnamespace pxt {\n//%\nButton *getButtonByPin(int pin, int flags) {\n unsigned highflags = (unsigned)pin >> 16;\n if (highflags & 0xff)\n flags = highflags & 0xff;\n\n pin &= 0xffff;\n\n auto cpid = DEVICE_ID_FIRST_BUTTON + pin;\n auto btn = (Button *)lookupComponent(cpid);\n if (btn == NULL) {\n auto pull = PullMode::None;\n if ((flags & 0xf0) == 0x10)\n pull = PullMode::Down;\n else if ((flags & 0xf0) == 0x20)\n pull = PullMode::Up;\n else if ((flags & 0xf0) == 0x30)\n pull = PullMode::None;\n else\n oops(3);\n // GCTODO\n btn = new Button(*lookupPin(pin), cpid, DEVICE_BUTTON_ALL_EVENTS,\n (ButtonPolarity)(flags & 0xf), pull);\n }\n return btn;\n}\n\n//%\nButton *getButtonByPinCfg(int key, int flags) {\n int pin = getConfig(key);\n if (pin == -1)\n soft_panic(PANIC_NO_SUCH_CONFIG);\n return getButtonByPin(pin, flags);\n}\n\nMultiButton *getMultiButton(int id, int pinA, int pinB, int flags) {\n auto btn = (MultiButton *)lookupComponent(id);\n if (btn == NULL) {\n auto bA = getButtonByPin(pinA, flags);\n auto bB = getButtonByPin(pinB, flags);\n // GCTODO\n btn = new MultiButton(bA->id, bB->id, id);\n\n // A user has registered to receive events from the buttonAB multibutton.\n // Disable click events from being generated by ButtonA and ButtonB, and defer the\n // control of this to the multibutton handler.\n //\n // This way, buttons look independent unless a buttonAB is requested, at which\n // point button A+B clicks can be correclty handled without breaking\n // causal ordering.\n bA->setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS);\n bB->setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS);\n btn->setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS);\n }\n return btn;\n}\n\n// This is for A, B, and AB\n//%\nAbstractButton *getButton(int id) {\n int pa = getConfig(CFG_PIN_BTN_A);\n int pb = getConfig(CFG_PIN_BTN_B);\n int flags = getConfig(CFG_DEFAULT_BUTTON_MODE, BUTTON_ACTIVE_LOW_PULL_UP);\n if (id == 0)\n return getButtonByPin(pa, flags);\n else if (id == 1)\n return getButtonByPin(pb, flags);\n else if (id == 2)\n return getMultiButton(DEVICE_ID_BUTTON_AB, pa, pb, flags);\n else {\n soft_panic(PANIC_INVALID_ARGUMENT);\n return NULL;\n }\n}\n\n} // namespace pxt\n\nnamespace DigitalInOutPinMethods {\n\n/**\n * Get the push button (connected to GND) for given pin\n */\n//%\nButton_ pushButton(DigitalInOutPin pin) {\n return pxt::getButtonByPin(pin->name, BUTTON_ACTIVE_LOW_PULL_UP);\n}\n\n} // namespace DigitalInOutPinMethods\n\n//% noRefCounting fixedInstances\nnamespace ButtonMethods {\n/**\n * Do something when a button (`A`, `B` or both `A` + `B`) is clicked, double clicked, etc...\n * @param button the button that needs to be clicked or used\n * @param event the kind of button gesture that needs to be detected\n * @param body code to run when the event is raised\n */\n//% help=input/button/on-event\n//% blockId=buttonEvent block=\"on %button|%event\"\n//% blockNamespace=input\n//% button.fieldEditor=\"gridpicker\"\n//% button.fieldOptions.width=220\n//% button.fieldOptions.columns=3\n//% weight=96 blockGap=12\n//% trackArgs=0\nvoid onEvent(Button_ button, ButtonEvent ev, Action body) {\n registerWithDal(button->id, (int)ev, body);\n}\n\n/**\n * Check if a button is pressed or not.\n * @param button the button to query the request\n */\n//% help=input/button/is-pressed\n//% block=\"%button|is pressed\"\n//% blockId=buttonIsPressed\n//% blockNamespace=input\n//% button.fieldEditor=\"gridpicker\"\n//% button.fieldOptions.width=220\n//% button.fieldOptions.columns=3\n//% weight=50 blockGap=8\n//% trackArgs=0\nbool isPressed(Button_ button) {\n return button->isPressed();\n}\n\n/**\n * See if the button was pressed again since the last time you checked.\n * @param button the button to query the request\n */\n//% help=input/button/was-pressed\n//% block=\"%button|was pressed\"\n//% blockId=buttonWasPressed\n//% blockNamespace=input\n//% button.fieldEditor=\"gridpicker\"\n//% button.fieldOptions.width=220\n//% button.fieldOptions.columns=3\n//% group=\"More\" weight=46 blockGap=8\n//% trackArgs=0\nbool wasPressed(Button_ button) {\n return button->wasPressed();\n}\n\n/**\n * Gets the component identifier for the button\n */\n//%\nint id(Button_ button) {\n return button->id;\n}\n\n} // namespace ButtonMethods\n",
1304
1304
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n /**\n * User interaction on buttons\n */\n\n declare const enum ButtonEvent {\n //% block=\"click\"\n Click = 3, // DEVICE_BUTTON_EVT_CLICK\n //% block=\"long click\"\n LongClick = 4, // DEVICE_BUTTON_EVT_LONG_CLICK\n //% block=\"up\"\n Up = 2, // DEVICE_BUTTON_EVT_UP\n //% block=\"down\"\n Down = 1, // DEVICE_BUTTON_EVT_DOWN\n }\n\n// Auto-generated. Do not edit. Really.\n",
1305
- "pxt.json": "{\n \"name\": \"buttons\",\n \"description\": \"Button A and B drivers\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"buttons.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1305
+ "pxt.json": "{\n \"name\": \"buttons\",\n \"description\": \"Button A and B drivers\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"buttons.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1306
1306
  "shims.d.ts": "// Auto-generated. Do not edit.\n\n\ndeclare interface DigitalInOutPin {\n /**\n * Get the push button (connected to GND) for given pin\n */\n //% shim=DigitalInOutPinMethods::pushButton\n pushButton(): Button;\n}\n\n\n\n //% noRefCounting fixedInstances\ndeclare interface Button {\n /**\n * Do something when a button (`A`, `B` or both `A` + `B`) is clicked, double clicked, etc...\n * @param button the button that needs to be clicked or used\n * @param event the kind of button gesture that needs to be detected\n * @param body code to run when the event is raised\n */\n //% help=input/button/on-event\n //% blockId=buttonEvent block=\"on %button|%event\"\n //% blockNamespace=input\n //% button.fieldEditor=\"gridpicker\"\n //% button.fieldOptions.width=220\n //% button.fieldOptions.columns=3\n //% weight=96 blockGap=12\n //% trackArgs=0 shim=ButtonMethods::onEvent\n onEvent(ev: ButtonEvent, body: () => void): void;\n\n /**\n * Check if a button is pressed or not.\n * @param button the button to query the request\n */\n //% help=input/button/is-pressed\n //% block=\"%button|is pressed\"\n //% blockId=buttonIsPressed\n //% blockNamespace=input\n //% button.fieldEditor=\"gridpicker\"\n //% button.fieldOptions.width=220\n //% button.fieldOptions.columns=3\n //% weight=50 blockGap=8\n //% trackArgs=0 shim=ButtonMethods::isPressed\n isPressed(): boolean;\n\n /**\n * See if the button was pressed again since the last time you checked.\n * @param button the button to query the request\n */\n //% help=input/button/was-pressed\n //% block=\"%button|was pressed\"\n //% blockId=buttonWasPressed\n //% blockNamespace=input\n //% button.fieldEditor=\"gridpicker\"\n //% button.fieldOptions.width=220\n //% button.fieldOptions.columns=3\n //% group=\"More\" weight=46 blockGap=8\n //% trackArgs=0 shim=ButtonMethods::wasPressed\n wasPressed(): boolean;\n\n /**\n * Gets the component identifier for the button\n */\n //% shim=ButtonMethods::id\n id(): int32;\n}\n\n// Auto-generated. Do not edit. Really.\n",
1307
1307
  "test.ts": ""
1308
1308
  },
@@ -1310,11 +1310,11 @@ var pxtTargetBundle = {
1310
1310
  "README.md": "# Colors\n\nColor manipulation",
1311
1311
  "colorbuffer.ts": "namespace color {\n export enum ColorBufferLayout {\n /**\n * 24bit RGB color\n */\n RGB,\n /**\n * 32bit RGB color with alpha\n */\n ARGB\n }\n\n /**\n * A buffer of colors\n */\n export class ColorBuffer {\n layout: ColorBufferLayout;\n buf: Buffer;\n\n constructor(length: number, layout?: ColorBufferLayout) {\n this.layout = layout || ColorBufferLayout.RGB;\n this.buf = control.createBuffer((length | 0) * this.stride);\n }\n\n static fromBuffer(buffer: Buffer, layout: ColorBufferLayout) {\n const b = new ColorBuffer(0, layout);\n b.buf = buffer.slice();\n return b;\n }\n\n get stride() {\n return this.layout == ColorBufferLayout.RGB ? 3 : 4;\n }\n\n get length() {\n return Math.idiv(this.buf.length, this.stride);\n }\n\n color(index: number): number {\n index = index | 0;\n if (index < 0 || index >= this.length)\n return -1;\n\n const s = this.stride;\n const start = index * s;\n let c = 0;\n for (let i = 0; i < s; ++i)\n c = (c << 8) | (this.buf[start + i] & 0xff);\n return c;\n }\n\n setColor(index: number, color: number) {\n index = index | 0;\n if (index < 0 || index >= this.length) return;\n\n const s = this.stride;\n const start = index * s;\n for (let i = s - 1; i >= 0; --i) {\n this.buf[start + i] = color & 0xff;\n color = color >> 8;\n }\n }\n\n slice(start?: number, length?: number): ColorBuffer {\n start = start | 0;\n if (start < 0)\n start = this.length - start;\n\n if (length == undefined)\n length = this.length;\n length = Math.min(length, this.length - start);\n\n const output = new ColorBuffer(length, this.layout);\n for (let i = 0; i < length; ++i) {\n output.setColor(i, this.color(start + i));\n }\n\n return output;\n }\n\n /**\n * Writes the content of the src color buffer starting at the start dstOffset in the current buffer\n * @param dstOffset\n * @param src\n */\n write(dstOffset: number, src: ColorBuffer): void {\n if (this.layout == src.layout) {\n const d = (dstOffset | 0) * this.stride;\n this.buf.write(d, src.buf);\n } else {\n // different color layout\n const n = Math.min(src.length, this.length - dstOffset);\n for (let i = 0; i < n; ++i)\n this.setColor(dstOffset + i, src.color(i));\n }\n }\n }\n\n /**\n * Converts an array of colors into a color buffer\n */\n export function createBuffer(colors: number[], layout?: ColorBufferLayout): color.ColorBuffer {\n const p = new ColorBuffer(colors.length, layout);\n const n = colors.length;\n for (let i = 0; i < n; i++) {\n p.setColor(i, colors[i]);\n }\n return p;\n }\n}",
1312
1312
  "colors.ts": "/**\n * Well known colors\n */\nconst enum Colors {\n //% block=red\n //% blockIdentity=color.wellKnown\n Red = 0xFF0000,\n //% block=orange\n //% blockIdentity=color.wellKnown\n Orange = 0xFF7F00,\n //% block=yellow\n //% blockIdentity=color.wellKnown\n Yellow = 0xFFFF00,\n //% block=green\n //% blockIdentity=color.wellKnown\n Green = 0x00FF00,\n //% block=blue\n //% blockIdentity=color.wellKnown\n Blue = 0x0000FF,\n //% block=indigo\n //% blockIdentity=color.wellKnown\n Indigo = 0x4b0082,\n //% block=violet\n //% blockIdentity=color.wellKnown\n Violet = 0x8a2be2,\n //% block=purple\n //% blockIdentity=color.wellKnown\n Purple = 0xA033E5,\n //% block=pink\n //% blockIdentity=color.wellKnown\n Pink = 0xFF007F,\n //% block=white\n //% blockIdentity=color.wellKnown\n White = 0xFFFFFF,\n //% block=black\n //% blockIdentity=color.wellKnown\n Black = 0x000000\n}\n\n/**\n * Well known color hues\n */\nconst enum ColorHues {\n //% block=red\n Red = 0,\n //% block=orange\n Orange = 29,\n //% block=yellow\n Yellow = 43,\n //% block=green\n Green = 86,\n //% block=aqua\n Aqua = 125,\n //% block=blue\n Blue = 170,\n //% block=purple\n Purple = 191,\n //% block=magenta\n Magenta = 213,\n //% block=pink\n Pink = 234\n}\n\n/**\n * Color manipulation\n */\n//% advanced=1\nnamespace color {\n /**\n * Converts red, green, blue channels into a RGB color\n * @param red value of the red channel between 0 and 255. eg: 255\n * @param green value of the green channel between 0 and 255. eg: 255\n * @param blue value of the blue channel between 0 and 255. eg: 255\n */\n //% blockId=\"colorsrgb\" block=\"red %red|green %green|blue %blue\"\n //% red.min=0 red.max=255 green.min=0 green.max=255 blue.min=0 blue.max=255\n //% help=\"colors/rgb\"\n //% weight=19 blockGap=8\n //% blockHidden=true\n export function rgb(red: number, green: number, blue: number): number {\n return ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);\n }\n\n export function argb(alpha: number, red: number, green: number, blue: number): number {\n return ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);\n }\n\n /**\n * Get the RGB value of a known color\n */\n //% blockId=colorscolors block=\"%color\"\n //% help=\"colors/well-known\"\n //% shim=TD_ID\n //% weight=20 blockGap=8\n //% blockHidden=true\n export function wellKnown(color: Colors): number {\n return color;\n }\n\n /**\n * Convert an HSV (hue, saturation, value) color to RGB\n * @param hue value of the hue channel between 0 and 255. eg: 255\n * @param sat value of the saturation channel between 0 and 255. eg: 255\n * @param val value of the value channel between 0 and 255. eg: 255\n */\n\n //% blockId=\"colorshsv\" block=\"hue %hue|sat %sat|val %val\"\n //% hue.min=0 hue.max=255 sat.min=0 sat.max=255 val.min=0 val.max=255\n //% help=\"colors/hsv\"\n //% weight=17\n //% blockHidden=true\n export function hsv(hue: number, sat: number = 255, val: number = 255): number {\n let h = (hue % 255) >> 0;\n if (h < 0) h += 255;\n // scale down to 0..192\n h = (h * 192 / 255) >> 0;\n\n //reference: based on FastLED's hsv2rgb rainbow algorithm [https://github.com/FastLED/FastLED](MIT)\n const invsat = 255 - sat;\n const brightness_floor = ((val * invsat) / 255) >> 0;\n const color_amplitude = val - brightness_floor;\n const section = (h / 0x40) >> 0; // [0..2]\n const offset = (h % 0x40) >> 0; // [0..63]\n\n const rampup = offset;\n const rampdown = (0x40 - 1) - offset;\n\n const rampup_amp_adj = ((rampup * color_amplitude) / (255 / 4)) >> 0;\n const rampdown_amp_adj = ((rampdown * color_amplitude) / (255 / 4)) >> 0;\n\n const rampup_adj_with_floor = (rampup_amp_adj + brightness_floor);\n const rampdown_adj_with_floor = (rampdown_amp_adj + brightness_floor);\n\n let r: number;\n let g: number;\n let b: number;\n if (section) {\n if (section == 1) {\n // section 1: 0x40..0x7F\n r = brightness_floor;\n g = rampdown_adj_with_floor;\n b = rampup_adj_with_floor;\n } else {\n // section 2; 0x80..0xBF\n r = rampup_adj_with_floor;\n g = brightness_floor;\n b = rampdown_adj_with_floor;\n }\n } else {\n // section 0: 0x00..0x3F\n r = rampdown_adj_with_floor;\n g = rampup_adj_with_floor;\n b = brightness_floor;\n }\n return rgb(r, g, b);\n }\n\n /**\n * Fade the color by the brightness\n * @param color color to fade\n * @param brightness the amount of brightness to apply to the color, eg: 128\n */\n //% blockId=\"colorsfade\" block=\"fade %color=neopixel_colors|by %brightness\"\n //% brightness.min=0 brightness.max=255\n //% help=\"light/fade\"\n //% group=\"Color\" weight=18 blockGap=8\n //% blockHidden=true\n export function fade(color: number, brightness: number): number {\n brightness = Math.max(0, Math.min(255, brightness >> 0));\n if (brightness < 255) {\n let red = unpackR(color);\n let green = unpackG(color);\n let blue = unpackB(color);\n\n red = (red * brightness) >> 8;\n green = (green * brightness) >> 8;\n blue = (blue * brightness) >> 8;\n\n color = rgb(red, green, blue);\n }\n return color;\n }\n\n export function blend(color: number, alpha: number, otherColor: number) {\n alpha = Math.max(0, Math.min(0xff, alpha | 0));\n const malpha = 0xff - alpha;\n const r = (unpackR(color) * malpha + unpackR(otherColor) * alpha) >> 8;\n const g = (unpackG(color) * malpha + unpackG(otherColor) * alpha) >> 8;\n const b = (unpackB(color) * malpha + unpackB(otherColor) * alpha) >> 8;\n return rgb(r, g, b);\n }\n\n export function gradient(startColor: number, endColor: number, steps: number): ColorBuffer {\n steps = Math.max(2, steps | 0);\n const b = new ColorBuffer(steps);\n b.setColor(0, startColor);\n b.setColor(b.length - 1, endColor);\n for (let i = 1; i < steps - 1; ++i) {\n const alpha = Math.idiv(0xff * i, steps);\n const c = blend(startColor, alpha, endColor);\n b.setColor(i, c);\n }\n return b;\n }\n\n export function unpackR(rgb: number): number {\n return (rgb >> 16) & 0xFF;\n }\n export function unpackG(rgb: number): number {\n return (rgb >> 8) & 0xFF;\n }\n export function unpackB(rgb: number): number {\n return (rgb >> 0) & 0xFF;\n }\n\n export function parseColor(color: string): number {\n switch (color) {\n case \"RED\":\n case \"red\":\n return Colors.Red;\n case \"GREEN\":\n case \"green\":\n return Colors.Green;\n case \"BLUE\":\n case \"blue\":\n return Colors.Blue;\n case \"WHITE\":\n case \"white\":\n return Colors.White;\n case \"ORANGE\":\n case \"orange\":\n return Colors.Orange;\n case \"PURPLE\":\n case \"purple\":\n return Colors.Purple;\n case \"YELLOW\":\n case \"yellow\":\n return Colors.Yellow;\n case \"PINK\":\n case \"pink\":\n return Colors.Pink;\n default:\n return parseInt(color) || 0;\n }\n }\n}",
1313
- "pxt.json": "{\n \"name\": \"color\",\n \"description\": \"Color manipulation\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"colors.ts\",\n \"colorbuffer.ts\",\n \"README.md\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"weight\": 1,\n \"icon\": \"/static/libs/color.png\"\n}\n"
1313
+ "pxt.json": "{\n \"name\": \"color\",\n \"description\": \"Color manipulation\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"colors.ts\",\n \"colorbuffer.ts\",\n \"README.md\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"weight\": 1,\n \"icon\": \"/static/libs/color.png\"\n}\n"
1314
1314
  },
1315
1315
  "color-coded-tilemap": {
1316
1316
  "README.md": "# Color-coded Tilemap\n\nBlocks for the color-coded tilemap.",
1317
- "pxt.json": "{\n \"name\": \"color-coded-tilemap\",\n \"description\": \"Blocks for the color-coded tilemap\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"tilemap.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 10,\n \"icon\": \"/static/libs/color-coded-tilemap.png\"\n}\n",
1317
+ "pxt.json": "{\n \"name\": \"color-coded-tilemap\",\n \"description\": \"Blocks for the color-coded tilemap\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"tilemap.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 10,\n \"icon\": \"/static/libs/color-coded-tilemap.png\"\n}\n",
1318
1318
  "tilemap.ts": "//% blockGap=8\nnamespace scene {\n /**\n * Package for color-coded tilemap blocks, to support existing curriculum.\n */\n\n /**\n * Set the map for placing tiles in the scene\n * @param map\n * @param scale\n */\n //% blockId=gamesettilemap block=\"set tile map to %map=tilemap_image_picker || with %scale pixel tiles\"\n //% scale.defl=TileScale.Sixteen\n //% group=\"Color-coded Tilemap\"\n //% help=scene/set-tile-map\n export function setTileMap(map: Image, scale = TileScale.Sixteen) {\n const scene = game.currentScene();\n if (!scene.tileMap || !(scene.tileMap as tiles.legacy.LegacyTilemap).isLegacy) {\n scene.tileMap = new tiles.legacy.LegacyTilemap();\n }\n (scene.tileMap as tiles.legacy.LegacyTilemap).setMap(map);\n scene.tileMap.scale = scale;\n }\n\n /**\n * Set an image as a tile at the given index. Tiles should be a 16x16 image\n * @param index\n * @param img\n */\n //% blockId=gamesettile block=\"set tile %index=colorindexpicker to %img=tile_image_picker with wall %wall=toggleOnOff\"\n //% group=\"Color-coded Tilemap\"\n //% help=scene/set-tile\n export function setTile(index: number, img: Image, wall?: boolean) {\n const scene = game.currentScene();\n if (!scene.tileMap || !(scene.tileMap as tiles.legacy.LegacyTilemap).isLegacy) {\n scene.tileMap = new tiles.legacy.LegacyTilemap();\n }\n (scene.tileMap as tiles.legacy.LegacyTilemap).setTile(index, img, !!wall);\n }\n\n /**\n * Get the tile at a position in the tile map\n * @param col\n * @param row\n */\n //% blockId=gamegettile block=\"tile col %col row %row\"\n //% group=\"Color-coded Tilemap\" blockSetVariable=\"myTile\"\n //% help=scene/get-tile\n export function getTile(col: number, row: number): tiles.Tile {\n const scene = game.currentScene();\n if (!scene.tileMap || !(scene.tileMap as tiles.legacy.LegacyTilemap).isLegacy) {\n scene.tileMap = new tiles.legacy.LegacyTilemap();\n }\n return (scene.tileMap as tiles.legacy.LegacyTilemap).getTileLegacy(col, row);\n }\n\n /**\n * Get all tiles in the tile map with the given index.\n * @param index\n */\n //% blockId=gamegettilestype block=\"array of all %index=colorindexpicker tiles\"\n //% group=\"Color-coded Tilemap\" blockSetVariable=\"tile list\"\n //% help=scene/get-tiles-by-type\n export function getTilesByType(index: number): tiles.Tile[] {\n const scene = game.currentScene();\n if (!scene.tileMap || !(scene.tileMap as tiles.legacy.LegacyTilemap).isLegacy) {\n scene.tileMap = new tiles.legacy.LegacyTilemap();\n }\n return (scene.tileMap as tiles.legacy.LegacyTilemap).getTilesByTypeLegacy(index);\n }\n\n /**\n * Center the given sprite on a random tile that is the given color\n * @param sprite\n * @param color\n */\n //% blockId=gameplaceonrandomtile block=\"place %sprite=variables_get(mySprite) on top of random $color tile\"\n //% group=\"Color-coded Tilemap\"\n //% color.shadow=\"colorindexpicker\"\n //% help=scene/place-on-random-tile\n export function placeOnRandomTile(sprite: Sprite, color: number): void {\n if (!sprite || !game.currentScene().tileMap) return;\n const tiles = getTilesByType(color);\n if (tiles.length > 0)\n Math.pickRandom(tiles).place(sprite);\n }\n\n /**\n * Set a tile at the given index\n * @param tile\n * @param index\n */\n //% blockId=gamesettileat block=\"set %tile=gamegettile to %index=colorindexpicker\"\n //% group=\"Color-coded Tilemap\"\n //% help=scene/set-tile-at\n export function setTileAt(tile: tiles.Tile, index: number) {\n const scene = game.currentScene();\n if (!scene.tileMap || !(scene.tileMap as tiles.legacy.LegacyTilemap).isLegacy) {\n scene.tileMap = new tiles.legacy.LegacyTilemap();\n }\n\n const tm: tiles.legacy.LegacyTilemap = scene.tileMap as tiles.legacy.LegacyTilemap;\n const scale = tm.scale;\n tm.setTileAt(tile.x >> scale, tile.y >> scale, index);\n }\n\n /**\n * Center the given sprite on this tile\n * @param sprite\n */\n //% blockId=legacyplaceontile block=\"on top of %tile=variables_get(myTile) place %sprite=variables_get(mySprite)\"\n //% group=\"Color-coded Tilemap\"\n //% help=tiles/place\n export function place(tile: tiles.Tile, mySprite: Sprite): void {\n if (!tile) return;\n tile.place(mySprite);\n }\n\n /**\n * Run code when a certain kind of sprite hits a tile\n * @param direction\n * @param tile\n * @param handler\n */\n //% group=\"Color-coded Tilemap\"\n //% draggableParameters=\"reporter\"\n //% blockId=spritesollisions block=\"on $sprite of kind $kind=spritekind hits wall $tile=colorindexpicker\"\n //% help=scene/on-hit-tile\n export function onHitTile(kind: number, tile: number, handler: (sprite: Sprite) => void) {\n if (kind == undefined || tile < 0 || tile > 0xF || !handler) return;\n\n const collisionHandlers = game.currentScene().collisionHandlers;\n if (!collisionHandlers[tile]) {\n collisionHandlers[tile] = [];\n }\n\n collisionHandlers[tile].push(\n new scene.SpriteHandler(\n kind,\n handler\n )\n );\n }\n\n /**\n * Get the obstacle sprite in a given direction if any\n * @param direction\n */\n //% blockId=legacyspriteobstacle block=\"%sprite=variables_get(mySprite) wall hit on %direction\"\n //% group=\"Color-coded Tilemap\"\n //% help=sprites/sprite/tile-hit-from\n export function tileHitFrom(sprite: Sprite, direction: CollisionDirection): number {\n if (!sprite) return 0;\n return sprite.tileHitFrom(direction);\n }\n}\n\nnamespace tiles.legacy {\n class TileSet {\n obstacle: boolean;\n private map: TileMap;\n private originalImage: Image;\n private cachedImage: Image;\n\n constructor(image: Image, collisions: boolean, map: tiles.TileMap) {\n this.originalImage = image;\n this.obstacle = collisions;\n this.map = map;\n }\n\n get image(): Image {\n const size = 1 << this.map.scale;\n if (!this.cachedImage || this.cachedImage.width != size || this.cachedImage.height != size) {\n if (this.originalImage.width == size && this.originalImage.height == size) {\n this.cachedImage = this.originalImage;\n } else {\n this.cachedImage = image.create(size, size);\n this.cachedImage.drawImage(this.originalImage, 0, 0);\n }\n }\n return this.cachedImage;\n }\n }\n\n export class LegacyTilemap extends tiles.TileMap {\n private _mapImage: Image;\n private _tileSets: TileSet[];\n\n public isLegacy: boolean;\n\n constructor(scale: TileScale = TileScale.Sixteen) {\n super(scale);\n this._tileSets = [];\n this.isLegacy = true;\n }\n\n get data(): TileMapData {\n return null;\n }\n\n get image(): Image {\n return this._mapImage;\n }\n\n offsetX(value: number) {\n return Math.clamp(0, Math.max(this.areaWidth() - screen.width, 0), value);\n }\n\n offsetY(value: number) {\n return Math.clamp(0, Math.max(this.areaHeight() - screen.height, 0), value);\n }\n\n areaWidth() {\n return this._mapImage ? (this._mapImage.width << this.scale) : 0;\n }\n\n areaHeight() {\n return this._mapImage ? (this._mapImage.height << this.scale) : 0;\n }\n\n get layer(): number {\n return this._layer;\n }\n\n set layer(value: number) {\n if (this._layer != value) {\n this._layer = value;\n }\n }\n\n get enabled(): boolean {\n return !!this._mapImage;\n }\n\n setTile(index: number, img: Image, collisions?: boolean) {\n if (this.isInvalidIndex(index)) return;\n this._tileSets[index] = new TileSet(img, collisions, this);\n }\n\n setMap(map: Image) {\n this._mapImage = map;\n }\n\n public getTileLegacy(col: number, row: number): Tile {\n return new Tile(col, row, this);\n }\n\n public getTile(col: number, row: number): Location {\n return new Location(col, row, this);\n }\n\n public setTileAt(col: number, row: number, index: number): void {\n if (!this.isOutsideMap(col, row) && !this.isInvalidIndex(index))\n this._mapImage.setPixel(col, row, index);\n }\n\n public getTilesByType(index: number): Location[] {\n if (this.isInvalidIndex(index) || !this.enabled) return [];\n\n let output: Location[] = [];\n for (let col = 0; col < this._mapImage.width; ++col) {\n for (let row = 0; row < this._mapImage.height; ++row) {\n let currTile = this._mapImage.getPixel(col, row);\n if (currTile === index) {\n output.push(new Location(col, row, this));\n }\n }\n }\n return output;\n }\n\n public getTilesByTypeLegacy(index: number): Tile[] {\n if (this.isInvalidIndex(index) || !this.enabled) return [];\n\n let output: Tile[] = [];\n for (let col = 0; col < this._mapImage.width; ++col) {\n for (let row = 0; row < this._mapImage.height; ++row) {\n let currTile = this._mapImage.getPixel(col, row);\n if (currTile === index) {\n output.push(new Tile(col, row, this));\n }\n }\n }\n return output;\n }\n\n private generateTile(index: number): TileSet {\n const size = 1 << this.scale\n\n const i = image.create(size, size);\n i.fill(index);\n return this._tileSets[index] = new TileSet(i, false, this);\n }\n\n private isOutsideMap(col: number, row: number): boolean {\n return !this.enabled || col < 0 || col >= this._mapImage.width\n || row < 0 || row >= this._mapImage.height;\n }\n\n protected isInvalidIndex(index: number): boolean {\n return index < 0 || index > 0xf;\n }\n\n protected draw(target: Image, camera: scene.Camera) {\n if (!this.enabled) return;\n\n // render tile map\n const bitmask = (0x1 << this.scale) - 1;\n const offsetX = camera.drawOffsetX & bitmask;\n const offsetY = camera.drawOffsetY & bitmask;\n\n const x0 = Math.max(0, camera.drawOffsetX >> this.scale);\n const xn = Math.min(this._mapImage.width, ((camera.drawOffsetX + target.width) >> this.scale) + 1);\n const y0 = Math.max(0, camera.drawOffsetY >> this.scale);\n const yn = Math.min(this._mapImage.height, ((camera.drawOffsetY + target.height) >> this.scale) + 1);\n\n for (let x = x0; x <= xn; ++x) {\n for (let y = y0; y <= yn; ++y) {\n const index = this._mapImage.getPixel(x, y);\n const tile = this._tileSets[index] || this.generateTile(index);\n if (tile) {\n target.drawTransparentImage(\n tile.image,\n ((x - x0) << this.scale) - offsetX,\n ((y - y0) << this.scale) - offsetY\n );\n }\n }\n }\n\n if (game.debug) {\n // render debug grid overlay\n for (let x = x0; x <= xn; ++x) {\n const xLine = ((x - x0) << this.scale) - offsetX;\n if (xLine >= 0 && xLine <= screen.width) {\n target.drawLine(\n xLine,\n 0,\n xLine,\n target.height,\n 1\n );\n }\n }\n\n for (let y = y0; y <= yn; ++y) {\n const yLine = ((y - y0) << this.scale) - offsetY;\n if (yLine >= 0 && yLine <= screen.height) {\n target.drawLine(\n 0,\n yLine,\n target.width,\n yLine,\n 1\n );\n }\n }\n }\n }\n\n public isObstacle(col: number, row: number) {\n if (!this.enabled) return false;\n if (this.isOutsideMap(col, row)) return true;\n\n let t = this._tileSets[this._mapImage.getPixel(col, row)];\n return t && t.obstacle;\n }\n\n public getObstacle(col: number, row: number) {\n const index = this.isOutsideMap(col, row) ? 0 : this._mapImage.getPixel(col, row);\n const tile = this._tileSets[index] || this.generateTile(index);\n return new sprites.StaticObstacle(\n tile.image,\n row << this.scale,\n col << this.scale,\n this.layer,\n index\n );\n }\n\n public isOnWall(s: Sprite) {\n if (!s.isStatic()) s.setHitbox();\n const hbox = s._hitbox\n\n const left = Fx.toIntShifted(hbox.left, this.scale);\n const right = Fx.toIntShifted(hbox.right, this.scale);\n const top = Fx.toIntShifted(hbox.top, this.scale);\n const bottom = Fx.toIntShifted(hbox.bottom, this.scale);\n\n for (let col = left; col <= right; ++col) {\n for (let row = top; row <= bottom; ++row) {\n if (this.isObstacle(col, row)) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n public getTileIndex(col: number, row: number) {\n return this._mapImage.getPixel(col, row);\n }\n\n public getTileImage(index: number) {\n if (!this._tileSets[index]) this.generateTile(index);\n return this._tileSets[index].image;\n }\n }\n}"
1319
1319
  },
1320
1320
  "controller": {
@@ -1325,7 +1325,7 @@ var pxtTargetBundle = {
1325
1325
  "crank.ts": "namespace controller {\n /**\n * Gets the current position of the crank.\n */\n //% blockId=controller_crank_position block=\"crank position\"\n //% weight=29 blockGap=8\n //% group=\"Extras\"\n export function crankPosition(): number {\n return controller.__internal.crankPosition();\n }\n}\n",
1326
1326
  "light.ts": "namespace controller {\n /**\n * Shows a color pulse\n * @param rgb RGB color of the LED\n */\n //% blockId=\"ctrllightpulse\" block=\"start light pulse %rgb=colorNumberPicker|for %duration=timePicker|ms\"\n //% weight=80 blockGap=8\n //% group=\"Extras\"\n export function startLightPulse(rgb: number, duration: number) {\n controller.__internal.startLightPulse(rgb, duration);\n }\n}\n\n//% advanced=true\nnamespace light {\n\n}",
1327
1327
  "lightsensor.ts": "enum ControllerLightCondition {\n //% block=\"dark\"\n Dark = 1, // SENSOR_THRESHOLD_LOW\n //% block=\"bright\"\n Bright = 2, // SENSOR_THRESHOLD_HIGH\n}\n\nnamespace controller {\n /**\n * Read the light level applied to the LED screen in a range from 0 (dark) to 255 (bright).\n */\n //% blockId=ctrllightlevel block=\"light level\"\n //% parts=\"lightsensor\"\n //% weight=30 blockGap=8\n //% group=\"Extras\"\n export function lightLevel(): number {\n return controller.__internal.lightLevel();\n }\n\n\n /**\n * Register an event that runs when light conditions (darker or brighter) change.\n * @param condition the condition that event triggers on\n */\n //% blockId=ctrlonlightcondition block=\"on light %condition\"\n //% parts=\"lightsensor\"\n //% weight=84 blockGap=12\n //% group=\"Extras\"\n export function onLightConditionChanged(condition: ControllerLightCondition, handler: () => void): void {\n controller.__internal.onLightConditionChanged(condition, handler);\n } \n}",
1328
- "pxt.json": "{\n \"name\": \"controller\",\n \"description\": \"Extra game controller functionalities\",\n \"dependencies\": {\n \"core\": \"*\",\n \"accelerometer\": \"*\",\n \"lightsensor\": \"*\",\n \"thermometer\": \"*\",\n \"game\": \"*\",\n \"light\": \"*\",\n \"rotary-encoder\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"state.ts\",\n \"vibration.ts\",\n \"accelerometer.ts\",\n \"lightsensor.ts\",\n \"thermometer.ts\",\n \"controller.ts\",\n \"light.ts\",\n \"crank.ts\",\n \"controllerimpl.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 99,\n \"icon\": \"/static/libs/controller.png\"\n}\n",
1328
+ "pxt.json": "{\n \"name\": \"controller\",\n \"description\": \"Extra game controller functionalities\",\n \"dependencies\": {\n \"core\": \"*\",\n \"accelerometer\": \"*\",\n \"lightsensor\": \"*\",\n \"thermometer\": \"*\",\n \"game\": \"*\",\n \"light\": \"*\",\n \"rotary-encoder\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"state.ts\",\n \"vibration.ts\",\n \"accelerometer.ts\",\n \"lightsensor.ts\",\n \"thermometer.ts\",\n \"controller.ts\",\n \"light.ts\",\n \"crank.ts\",\n \"controllerimpl.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 99,\n \"icon\": \"/static/libs/controller.png\"\n}\n",
1329
1329
  "state.ts": "namespace controller {\n export interface ControllerSceneState {\n lastGesture?: ControllerGesture;\n gestureHandlers?: any;\n lastCustomGesture?: number;\n customGestureHandlers?: any;\n lastLightCondition?: ControllerLightCondition;\n lightHandlers?: any;\n }\n\n export interface CustomGestureHandler {\n update: () => boolean;\n handler: () => void;\n }\n\n export function sceneState(): ControllerSceneState {\n const sc = game.currentScene();\n let state = sc.data[\"controller.state\"];\n if (!state) {\n state = sc.data[\"controller.state\"] = <ControllerSceneState>{\n };\n }\n return state;\n }\n\n\n function updateController() {\n const state = sceneState();\n // accelerometer\n if (state.lastGesture !== undefined) {\n const handler = state.gestureHandlers && state.gestureHandlers[state.lastGesture];\n if (handler) {\n state.lastGesture = undefined;\n handler();\n }\n }\n if (state.lastCustomGesture !== undefined) {\n const customHandler = state.customGestureHandlers && state.customGestureHandlers[state.lastCustomGesture] as CustomGestureHandler;\n if (customHandler) {\n state.lastCustomGesture = undefined;\n customHandler.handler();\n }\n }\n\n // light sensor\n if (state.lightHandlers\n && state.lastLightCondition !== undefined\n && state.lightHandlers[state.lastLightCondition]) {\n const handler = state.lightHandlers[state.lastLightCondition];\n state.lastLightCondition = undefined;\n handler();\n }\n }\n\n function initController(s: scene.Scene) {\n s.eventContext.registerFrameHandler(scene.UPDATE_CONTROLLER_PRIORITY, updateController);\n }\n\n scene.Scene.initializers.push(initController);\n}",
1330
1330
  "thermometer.ts": "const enum ControllerTemperatureUnit {\n //% block=\"°C\"\n Celsius = 0,\n //% block=\"°F\"\n Fahrenheit = 1,\n}\n\n\nnamespace controller {\n /**\n * Get the temperature in Celsius or Fahrenheit degrees.\n */\n //% blockId=ctrltemperature block=\"temperature in %unit\"\n //% parts=\"thermometer\"\n //% weight=26\n //% group=\"Extras\"\n export function temperature(unit: ControllerTemperatureUnit): number {\n return controller.__internal.temperature(unit);\n }\n}",
1331
1331
  "vibration.ts": "namespace controller {\n /**\n * Vibrates the controller for the given duration (in milli seconds)\n * @param millis \n */\n //% blockId=ctrlvibrate block=\"vibrate $millis ms\"\n //% millis.shadow=timePicker\n //% group=\"Extras\"\n export function vibrate(millis: number) {\n controller.__internal.vibrate(millis);\n }\n}"
@@ -1338,7 +1338,7 @@ var pxtTargetBundle = {
1338
1338
  "crank.ts": "namespace controller {\n /**\n * Gets the current position of the crank.\n */\n //% blockId=controller_crank_position block=\"crank position\"\n //% weight=29 blockGap=8\n //% group=\"Extras\"\n export function crankPosition(): number {\n return controller.__internal.crankPosition();\n }\n}\n",
1339
1339
  "light.ts": "namespace controller {\n /**\n * Shows a color pulse\n * @param rgb RGB color of the LED\n */\n //% blockId=\"ctrllightpulse\" block=\"start light pulse %rgb=colorNumberPicker|for %duration=timePicker|ms\"\n //% weight=80 blockGap=8\n //% group=\"Extras\"\n export function startLightPulse(rgb: number, duration: number) {\n controller.__internal.startLightPulse(rgb, duration);\n }\n}\n\n//% advanced=true\nnamespace light {\n\n}",
1340
1340
  "lightsensor.ts": "enum ControllerLightCondition {\n //% block=\"dark\"\n Dark = 1, // SENSOR_THRESHOLD_LOW\n //% block=\"bright\"\n Bright = 2, // SENSOR_THRESHOLD_HIGH\n}\n\nnamespace controller {\n /**\n * Read the light level applied to the LED screen in a range from 0 (dark) to 255 (bright).\n */\n //% blockId=ctrllightlevel block=\"light level\"\n //% parts=\"lightsensor\"\n //% weight=30 blockGap=8\n //% group=\"Extras\"\n export function lightLevel(): number {\n return controller.__internal.lightLevel();\n }\n\n\n /**\n * Register an event that runs when light conditions (darker or brighter) change.\n * @param condition the condition that event triggers on\n */\n //% blockId=ctrlonlightcondition block=\"on light %condition\"\n //% parts=\"lightsensor\"\n //% weight=84 blockGap=12\n //% group=\"Extras\"\n export function onLightConditionChanged(condition: ControllerLightCondition, handler: () => void): void {\n controller.__internal.onLightConditionChanged(condition, handler);\n } \n}",
1341
- "pxt.json": "{\n \"name\": \"controller---none\",\n \"description\": \"Extra game controller functionalities\",\n \"dependencies\": {\n \"core\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"state.ts\",\n \"vibration.ts\",\n \"accelerometer.ts\",\n \"lightsensor.ts\",\n \"thermometer.ts\",\n \"controller.ts\",\n \"light.ts\",\n \"crank.ts\",\n \"controllerimpl.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1341
+ "pxt.json": "{\n \"name\": \"controller---none\",\n \"description\": \"Extra game controller functionalities\",\n \"dependencies\": {\n \"core\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"state.ts\",\n \"vibration.ts\",\n \"accelerometer.ts\",\n \"lightsensor.ts\",\n \"thermometer.ts\",\n \"controller.ts\",\n \"light.ts\",\n \"crank.ts\",\n \"controllerimpl.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1342
1342
  "state.ts": "namespace controller {\n export interface ControllerSceneState {\n lastGesture?: ControllerGesture;\n gestureHandlers?: any;\n lastCustomGesture?: number;\n customGestureHandlers?: any;\n lastLightCondition?: ControllerLightCondition;\n lightHandlers?: any;\n }\n\n export interface CustomGestureHandler {\n update: () => boolean;\n handler: () => void;\n }\n\n export function sceneState(): ControllerSceneState {\n const sc = game.currentScene();\n let state = sc.data[\"controller.state\"];\n if (!state) {\n state = sc.data[\"controller.state\"] = <ControllerSceneState>{\n };\n }\n return state;\n }\n\n\n function updateController() {\n const state = sceneState();\n // accelerometer\n if (state.lastGesture !== undefined) {\n const handler = state.gestureHandlers && state.gestureHandlers[state.lastGesture];\n if (handler) {\n state.lastGesture = undefined;\n handler();\n }\n }\n if (state.lastCustomGesture !== undefined) {\n const customHandler = state.customGestureHandlers && state.customGestureHandlers[state.lastCustomGesture] as CustomGestureHandler;\n if (customHandler) {\n state.lastCustomGesture = undefined;\n customHandler.handler();\n }\n }\n\n // light sensor\n if (state.lightHandlers\n && state.lastLightCondition !== undefined\n && state.lightHandlers[state.lastLightCondition]) {\n const handler = state.lightHandlers[state.lastLightCondition];\n state.lastLightCondition = undefined;\n handler();\n }\n }\n\n function initController(s: scene.Scene) {\n s.eventContext.registerFrameHandler(scene.UPDATE_CONTROLLER_PRIORITY, updateController);\n }\n\n scene.Scene.initializers.push(initController);\n}",
1343
1343
  "thermometer.ts": "const enum ControllerTemperatureUnit {\n //% block=\"°C\"\n Celsius = 0,\n //% block=\"°F\"\n Fahrenheit = 1,\n}\n\n\nnamespace controller {\n /**\n * Get the temperature in Celsius or Fahrenheit degrees.\n */\n //% blockId=ctrltemperature block=\"temperature in %unit\"\n //% parts=\"thermometer\"\n //% weight=26\n //% group=\"Extras\"\n export function temperature(unit: ControllerTemperatureUnit): number {\n return controller.__internal.temperature(unit);\n }\n}",
1344
1344
  "vibration.ts": "namespace controller {\n /**\n * Vibrates the controller for the given duration (in milli seconds)\n * @param millis \n */\n //% blockId=ctrlvibrate block=\"vibrate $millis ms\"\n //% millis.shadow=timePicker\n //% group=\"Extras\"\n export function vibrate(millis: number) {\n controller.__internal.vibrate(millis);\n }\n}"
@@ -1372,7 +1372,7 @@ var pxtTargetBundle = {
1372
1372
  "platform.cpp": "#include \"pxt.h\"\n#include \"light.h\"\n\nnamespace pxt {\n\nCODAL_TIMER devTimer;\n\nstatic void initRandomSeed() {\n int seed = 0xC0DA1;\n auto pinTemp = LOOKUP_PIN(TEMPERATURE);\n if (pinTemp)\n seed *= pinTemp->getAnalogValue();\n auto pinLight = LOOKUP_PIN(LIGHT);\n if (pinLight)\n seed *= pinLight->getAnalogValue();\n seedRandom(seed);\n}\n\nstatic void remapSwdPin(int pinCfg, int fallback) {\n int pinName = getConfig(pinCfg);\n if (pinName == PA30 || pinName == PA31) {\n if (getConfig(CFG_SWD_ENABLED, 0)) {\n linkPin(pinName, fallback);\n } else {\n PORT->Group[pinName / 32].PINCFG[pinName % 32].reg = (uint8_t)PORT_PINCFG_INEN;\n }\n }\n}\n\nstatic void initSwdPins() {\n remapSwdPin(CFG_PIN_NEOPIXEL, PIN(D0));\n remapSwdPin(CFG_PIN_RXLED, PIN(D1));\n remapSwdPin(CFG_PIN_SPEAKER_AMP, PIN(D2));\n}\n\nvoid platform_init() {\n initSwdPins();\n initRandomSeed();\n light::clear();\n\n if (*HF2_DBG_MAGIC_PTR == HF2_DBG_MAGIC_START) {\n *HF2_DBG_MAGIC_PTR = 0;\n // this will cause alignment fault at the first breakpoint\n globals[0] = (TValue)1;\n }\n}\n\n} // namespace pxt\n",
1373
1373
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n// This is specific for SAMD21, to be replaced in other Codal targets.\n\n#include \"CapTouchButton.h\"\n#include \"Image.h\"\n#include \"MbedTimer.h\"\n#include \"MbedI2C.h\"\n#include \"MbedPin.h\"\n#include \"MbedSPI.h\"\n#include \"MbedSerial.h\"\n#include \"MultiButton.h\"\n#include \"CPlayI2C.h\"\n\n#include \"SAMD21DMAC.h\"\n\n// Analog Pins, all SAMD21: PA02-PA11 PB00-PB09 (some pins not connected)\n// 2 ports times 32 pins in each\n#define DEV_NUM_PINS 64\n// pins marked with AIN and PTC in the data sheet\n#define DEV_ANALOG_PINS 0x3ff00000ffcULL\n\n#define PAGE_SIZE 256\n\n#define CODAL_DMAC SAMD21DMAC\n\n// this is codal::_mbed for both mbed and mbedos now\n#define CODAL_MBED codal::_mbed\n\n#define CODAL_I2C codal::CPlayI2C\n\n#ifndef IMAGE_BITS\n#define IMAGE_BITS 1\n#endif\n\n#ifdef JUST_FOR_DAL_D_TS_CPP_WILL_IGNORE\n#define PA00 0\n#define PA01 1\n#define PA02 2\n#define PA03 3\n#define PA04 4\n#define PA05 5\n#define PA06 6\n#define PA07 7\n#define PA08 8\n#define PA09 9\n#define PA10 10\n#define PA11 11\n#define PA12 12\n#define PA13 13\n#define PA14 14\n#define PA15 15\n#define PA16 16\n#define PA17 17\n#define PA18 18\n#define PA19 19\n#define PA20 20\n#define PA21 21\n#define PA22 22\n#define PA23 23\n#define PA24 24\n#define PA25 25\n#define PA26 26\n#define PA27 27\n#define PA28 28\n#define PA29 29\n#define PA30 30\n#define PA31 31\n#define PB00 32\n#define PB01 33\n#define PB02 34\n#define PB03 35\n#define PB04 36\n#define PB05 37\n#define PB06 38\n#define PB07 39\n#define PB08 40\n#define PB09 41\n#define PB10 42\n#define PB11 43\n#define PB12 44\n#define PB13 45\n#define PB14 46\n#define PB15 47\n#define PB16 48\n#define PB17 49\n#define PB18 50\n#define PB19 51\n#define PB20 52\n#define PB21 53\n#define PB22 54\n#define PB23 55\n#define PB24 56\n#define PB25 57\n#define PB26 58\n#define PB27 59\n#define PB28 60\n#define PB29 61\n#define PB30 62\n#define PB31 63\n#endif\n\n#endif\n",
1374
1374
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#include \"CodalConfig.h\"\n#include \"CodalHeapAllocator.h\"\n#include \"CodalDevice.h\"\n#include \"CodalDmesg.h\"\n#include \"ErrorNo.h\"\n#include \"Timer.h\"\n#include \"Matrix4.h\"\n#include \"CodalCompat.h\"\n#include \"CodalComponent.h\"\n#include \"ManagedType.h\"\n#include \"Event.h\"\n#include \"NotifyEvents.h\"\n#include \"Button.h\"\n#include \"CodalFiber.h\"\n#include \"MessageBus.h\"\n#include \"MultiButton.h\"\n\nusing namespace codal;\n\n// codal::ManagedString compat\n#define MSTR(s) codal::ManagedString((s)->data, (s)->length)\n#define PSTR(s) mkString((s).toCharArray(), (s).length())\n\n#include \"pins.h\"\n\n#if CONFIG_ENABLED(DEVICE_USB)\n#include \"hf2.h\"\n#include \"hf2dbg.h\"\n#if CONFIG_ENABLED(DEVICE_MOUSE)\n#include \"HIDMouse.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\n#include \"HIDKeyboard.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\n#include \"HIDJoystick.h\"\n#endif\n#endif\n\n#define PXT_COMM_BASE 0x20002000 // 8k in\n\n// old codal compat\n#ifndef REAL_TIME_FUNC\n#define REAL_TIME_FUNC /* */\n#endif\n\nnamespace pxt {\n\n#if CONFIG_ENABLED(DEVICE_USB)\nextern CodalUSB usb;\nextern HF2 hf2;\n#if CONFIG_ENABLED(DEVICE_MOUSE)\nextern USBHIDMouse mouse;\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\nextern USBHIDKeyboard keyboard;\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\nextern USBHIDJoystick joystick;\n#endif\n#endif\n\n// Utility functions\nextern Event lastEvent;\nextern CODAL_TIMER devTimer;\nextern MessageBus devMessageBus;\nextern codal::CodalDevice device;\n\nvoid set_usb_strings(const char *uf2_info);\nextern void (*logJDFrame)(const uint8_t *data);\nextern void (*sendJDFrame)(const uint8_t *data);\n\nstatic inline void raiseEvent(int src, int val) {\n Event(src, val);\n}\n\n} // namespace pxt\n\nnamespace pins {\nclass CodalSPIProxy;\nclass CodalI2CProxy;\n} // namespace pins\n\ntypedef pins::CodalI2CProxy* I2C_;\ntypedef pins::CodalSPIProxy* SPI_;\n\nnamespace pxt {\ncodal::LowLevelTimer *allocateTimer();\n\n#ifdef CODAL_I2C\nCODAL_I2C* getI2C(DigitalInOutPin sda, DigitalInOutPin scl);\n#endif\nCODAL_SPI* getSPI(DigitalInOutPin mosi, DigitalInOutPin miso, DigitalInOutPin sck);\n#ifdef CODAL_JACDAC_WIRE_SERIAL\nLowLevelTimer* getJACDACTimer();\n#endif\nclass PressureButton;\nuint32_t readButtonMultiplexer(int bits);\nvoid disableButtonMultiplexer();\n}\n\nnamespace serial {\nclass CodalSerialDeviceProxy;\n}\n\ntypedef serial::CodalSerialDeviceProxy* SerialDevice;\n\nnamespace jacdac {\nclass JDProxyDriver;\n} // namespace network\n\ntypedef jacdac::JDProxyDriver* JacDacDriverStatus;\n\n#define DEVICE_ID_BUTTON_SLIDE 3000\n#define DEVICE_ID_MICROPHONE 3001\n#define DEVICE_ID_FIRST_BUTTON 4000\n#define DEVICE_ID_FIRST_TOUCHBUTTON 4100\n\n#define PXT_INTERNAL_KEY_UP 2050\n#define PXT_INTERNAL_KEY_DOWN 2051\n\n#endif\n",
1375
- "pxt.json": "{\n \"name\": \"core\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1375
+ "pxt.json": "{\n \"name\": \"core\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1376
1376
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include \"CodalDmesg.h\"\n#include \"CodalHeapAllocator.h\"\n\n#define PXT_CODAL 1\n\n#define itoa(a, b) codal::itoa(a, b)\n\n#define GC_GET_HEAP_SIZE() device_heap_size(0)\n#define GC_STACK_BASE DEVICE_STACK_BASE\n#define xmalloc device_malloc\n#define xfree device_free\n\n// on most devices we allocate the entire heap at once, so large allocs should work\n// if they don't you just get the regular out of memory instead of alloc too large\n#define GC_MAX_ALLOC_SIZE (128 * 1024)\n\n#endif\n",
1377
1377
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1378
1378
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace light {\n\n /**\n * Send a programmable light buffer to the specified digital pin\n * @param data The pin that the lights are connected to\n * @param clk the clock line if any\n * @param mode the color encoding mode\n * @param buf The buffer to send to the pin\n */\n //% shim=light::sendBuffer\n function sendBuffer(data: DigitalInOutPin, clk: DigitalInOutPin, mode: int32, buf: Buffer): void;\n}\ndeclare namespace control {\n\n /**\n * Determines if the USB has been enumerated.\n */\n //% shim=control::isUSBInitialized\n function isUSBInitialized(): boolean;\n}\ndeclare namespace pins {\n\n /**\n * Get a pin by configuration id (DAL.CFG_PIN...)\n */\n //% shim=pins::pinByCfg\n function pinByCfg(key: int32): DigitalInOutPin;\n\n /**\n * Create a new zero-initialized buffer.\n * @param size number of bytes in the buffer\n */\n //% shim=pins::createBuffer\n function createBuffer(size: int32): Buffer;\n\n /**\n * Get the duration of the last pulse in microseconds. This function should be called from a\n * ``onPulsed`` handler.\n */\n //% help=pins/pulse-duration blockGap=8\n //% blockId=pins_pulse_duration block=\"pulse duration (µs)\"\n //% weight=19 shim=pins::pulseDuration\n function pulseDuration(): int32;\n}\n\n\ndeclare interface AnalogInPin {\n /**\n * Read the connector value as analog, that is, as a value comprised between 0 and 1023.\n * @param name pin to write to\n */\n //% help=pins/analog-read weight=53\n //% blockId=device_get_analog_pin block=\"analog read|pin %name\" blockGap=\"8\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=AnalogInPinMethods::analogRead\n analogRead(): int32;\n}\n\n\ndeclare interface AnalogOutPin {\n /**\n * Set the connector value as analog. Value must be comprised between 0 and 1023.\n * @param name pin name to write to\n * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0\n */\n //% help=pins/analog-write weight=52\n //% blockId=device_set_analog_pin block=\"analog write|pin %name|to %value\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.min=0 value.max=1023 shim=AnalogOutPinMethods::analogWrite\n analogWrite(value: int32): void;\n}\n\n\ndeclare interface DigitalInOutPin {\n /**\n * Read a pin or connector as either 0 or 1\n * @param name pin to read from\n */\n //% help=pins/digital-read weight=61\n //% blockId=device_get_digital_pin block=\"digital read|pin %name\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalRead\n digitalRead(): boolean;\n\n /**\n * Set a pin or connector value to either 0 or 1.\n * @param name pin to write to\n * @param value value to set on the pin\n */\n //% help=pins/digital-write weight=60\n //% blockId=device_set_digital_pin block=\"digital write|pin %name|to %value=toggleHighLow\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalWrite\n digitalWrite(value: boolean): void;\n\n /**\n * Make this pin a digital input, and create events where the timestamp is the duration\n * that this pin was either ``high`` or ``low``.\n */\n //% help=pins/on-pulsed weight=16 blockGap=8\n //% blockId=pins_on_pulsed block=\"on|pin %pin|pulsed %pulse\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4\n //% deprecated=1 hidden=1 shim=DigitalInOutPinMethods::onPulsed\n onPulsed(pulse: PulseValue, body: () => void): void;\n\n /**\n * Register code to run when a pin event occurs. \n */\n //% help=pins/on-event weight=20 blockGap=8\n //% blockId=pinsonevent block=\"on|pin %pin|%event\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 shim=DigitalInOutPinMethods::onEvent\n onEvent(event: PinEvent, body: () => void): void;\n\n /**\n * Return the duration of a pulse in microseconds\n * @param name the pin which measures the pulse\n * @param value the value of the pulse (default high)\n * @param maximum duration in micro-seconds\n */\n //% blockId=\"pins_pulse_in\" block=\"pulse in (µs)|pin %name|pulsed %high||timeout %maxDuration (µs)\"\n //% weight=18 blockGap=8\n //% help=\"pins/pulse-in\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 maxDuration.defl=2000000 shim=DigitalInOutPinMethods::pulseIn\n pulseIn(value: PulseValue, maxDuration?: int32): int32;\n\n /**\n * Set the pull direction of this pin.\n * @param name pin to set the pull mode on\n * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone\n */\n //% help=pins/set-pull weight=17 blockGap=8\n //% blockId=device_set_pull block=\"set pull|pin %pin|to %pull\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::setPull\n setPull(pull: PinPullMode): void;\n}\n\n\ndeclare interface PwmPin {}\n\n\ndeclare interface PwmOnlyPin {\n /**\n * Set the Pulse-width modulation (PWM) period of the analog output. The period is in\n * **microseconds** or `1/1000` milliseconds.\n * If this pin is not configured as an analog output (using `analog write pin`), the operation has\n * no effect.\n * @param name analog pin to set period to\n * @param micros period in micro seconds. eg:20000\n */\n //% help=pins/analog-set-period weight=51\n //% blockId=device_set_analog_period block=\"analog set period|pin %pin|to (µs)%period\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::analogSetPeriod\n analogSetPeriod(period: int32): void;\n\n /**\n * Write a value to the servo to control the rotation of the shaft. On a standard servo, this will\n * set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous\n * rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one\n * direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).\n * @param name pin to write to\n * @param value angle or rotation speed\n */\n //% help=pins/servo-write weight=41 group=\"Servo\"\n //% blockId=device_set_servo_pin block=\"servo write|pin %name|to %value=protractorPicker\" blockGap=8\n //% parts=microservo trackArgs=0\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.defl=90 shim=PwmOnlyPinMethods::servoWrite\n servoWrite(value?: int32): void;\n\n /**\n * Set the pin for PWM analog output, make the period be 20 ms, and set the pulse width.\n * The pulse width is based on the value it is given **microseconds** or `1/1000` milliseconds.\n * @param name pin name\n * @param duration pulse duration in micro seconds, eg:1500\n */\n //% help=pins/servo-set-pulse weight=40 group=\"Servo\" blockGap=8\n //% blockId=device_set_servo_pulse block=\"servo set pulse|pin %value|to (µs) %duration\"\n //% parts=microservo blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::servoSetPulse\n servoSetPulse(duration: int32): void;\n\n /**\n * Indicates if the servo is running continuously\n */\n //% blockHidden=1 shim=PwmOnlyPinMethods::servoSetContinuous\n servoSetContinuous(continuous: boolean): void;\n}\ndeclare namespace control {\n\n /**\n * Announce that an event happened to registered handlers.\n * @param src ID of the MicroBit Component that generated the event\n * @param value Component specific code indicating the cause of the event.\n */\n //% weight=21 blockGap=12 blockId=\"control_raise_event\"\n //% help=control/raise-event\n //% block=\"raise event|from %src|with value %value\" blockExternalInputs=1 shim=control::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Determine the version of system software currently running.\n */\n //% blockId=\"control_device_dal_version\" block=\"device dal version\"\n //% help=control/device-dal-version shim=control::deviceDalVersion\n function deviceDalVersion(): string;\n\n /**\n * Allocates the next user notification event\n */\n //% help=control/allocate-notify-event shim=control::allocateNotifyEvent\n function allocateNotifyEvent(): int32;\n\n /** Write a message to DMESG debugging buffer. */\n //% shim=control::dmesg\n function dmesg(s: string): void;\n\n /** Write a message and value (pointer) to DMESG debugging buffer. */\n //% shim=control::dmesgPtr\n function dmesgPtr(str: string, ptr: Object): void;\n}\n\n\ndeclare interface I2C {\n /**\n * Read `size` bytes from a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::readBuffer\n readBuffer(address: int32, size: int32, repeat?: boolean): Buffer;\n\n /**\n * Write bytes to a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::writeBuffer\n writeBuffer(address: int32, buf: Buffer, repeat?: boolean): int32;\n}\ndeclare namespace pins {\n\n /**\n * Opens a Serial communication driver\n */\n //% help=pins/create-i2c\n //% parts=i2c shim=pins::createI2C\n function createI2C(sda: DigitalInOutPin, scl: DigitalInOutPin): I2C;\n}\ndeclare namespace pins {\n\n /**\n * Opens a SPI driver\n */\n //% help=pins/create-spi\n //% parts=spi shim=pins::createSPI\n function createSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin): SPI;\n\n /**\n * Opens a slave SPI driver\n */\n //% parts=spi shim=pins::createSlaveSPI\n function createSlaveSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin, csPin: DigitalInOutPin): SPI;\n}\n\n\ndeclare interface SPI {\n /**\n * Write to the SPI bus\n */\n //% shim=SPIMethods::write\n write(value: int32): int32;\n\n /**\n * Transfer buffers over the SPI bus\n */\n //% argsNullable shim=SPIMethods::transfer\n transfer(command: Buffer, response: Buffer): void;\n\n /**\n * Sets the SPI clock frequency\n */\n //% shim=SPIMethods::setFrequency\n setFrequency(frequency: int32): void;\n\n /**\n * Sets the SPI bus mode\n */\n //% shim=SPIMethods::setMode\n setMode(mode: int32): void;\n}\ndeclare namespace configStorage {\n\n /**\n * Puts an entry in the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n * @param value the data (max 32 characters)\n */\n //% shim=configStorage::setBuffer\n function setBuffer(key: string, value: Buffer): void;\n\n /**\n * Gets an entry from the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::getBuffer\n function getBuffer(key: string): Buffer;\n\n /**\n * Removes the key from local storage\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::removeItem\n function removeItem(key: string): void;\n\n /**\n * Clears the local storage\n */\n //% shim=configStorage::clear\n function clear(): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1400,7 +1400,7 @@ var pxtTargetBundle = {
1400
1400
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n#define OUTPUT_BITS 12\n\n#define PAGE_SIZE 1024 // not really\n\n#define DEV_NUM_PINS 28\n\n#define DEV_PWM_PINS 0xffffffffULL\n#define DEV_AIN_PINS 0ULL\n\n\n// Codal doesn't yet distinguish between PWM and AIN\n#define DEV_ANALOG_PINS (DEV_PWM_PINS | DEV_AIN_PINS)\n\n#define CODAL_PIN ZPin\n#define CODAL_TIMER ZTimer\n#define CODAL_SPI ZSPI\n#define CODAL_I2C ZI2C\n\n\nnamespace pxt\n{\n\n class ZPin;\n class AbstractButton;\n class MultiButton;\n class CodalComponent;\n \n \n} // pxt\n\n#define IMAGE_BITS 4\n#define PXT_GC_THREAD_LIST 1\n\n#define PXT_IN_ISR() false\n\n#define PROGDIR \"/sd/prj\"\n#undef SETTINGSDIR\n\n// #define SETTINGSDIR \"/sd/cfg\"\n\n#endif\n",
1401
1401
  "platform_includes.h": "#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#include <sys/types.h>\n\n#define PROCESSOR_WORD_TYPE uintptr_t\n",
1402
1402
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#define OUTPUT_BITS 12\n\n#define DEVICE_EVT_ANY 0\n#define DEVICE_ID_NOTIFY_ONE 1022\n#define DEVICE_ID_NOTIFY 1023\n\nnamespace serial {\nclass LinuxSerialDevice;\n}\n\ntypedef serial::LinuxSerialDevice *SerialDevice;\n\nnamespace pxt {\nvoid raiseEvent(int id, int event);\nint allocateNotifyEvent();\nvoid sleep_core_us(uint64_t us);\nvoid startUser();\nvoid stopUser();\nint tryLockUser();\n\nvoid target_disable_irq();\nvoid target_enable_irq();\n\nconst char *getConfigString(const char *name);\nint getConfigInt(const char *name, int defl);\n#define ENDMARK -0x7fff0123\nconst int *getConfigInts(const char *name);\n\nclass Button;\ntypedef Button *Button_;\n\nextern \"C\" void target_init();\n\nextern volatile bool paniced;\nextern char **initialArgv;\nvoid target_exit();\n\n// Buffer, Sound, and Image share representation.\ntypedef Buffer Sound;\n\n// extern Event lastEvent;\n} // namespace pxt\n\n#undef PXT_MAIN\n#define PXT_MAIN \\\n int main(int argc, char **argv) { \\\n pxt::initialArgv = argv; \\\n pxt::start(); \\\n return 0; \\\n }\n\n#endif\n",
1403
- "pxt.json": "{\n \"name\": \"core---linux\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"Makefile\",\n \"dal.d.ts\",\n \"linux.cpp\",\n \"config.cpp\",\n \"target.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"control.cpp\",\n \"dmesg.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\",\n \"timer.ts\",\n \"platform_includes.h\",\n \"codalemu.cpp\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1403
+ "pxt.json": "{\n \"name\": \"core---linux\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"Makefile\",\n \"dal.d.ts\",\n \"linux.cpp\",\n \"config.cpp\",\n \"target.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"control.cpp\",\n \"dmesg.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\",\n \"timer.ts\",\n \"platform_includes.h\",\n \"codalemu.cpp\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1404
1404
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n\nnamespace pxt {\nvoid *gcAllocBlock(size_t sz);\nvoid vm_stack_trace();\n}\n\nextern \"C\" void dmesg(const char *fmt, ...);\nextern \"C\" void vdmesg(const char *format, va_list arg);\n#define DMESG ::dmesg\n\nstatic inline void itoa(int v, char *dst) {\n snprintf(dst, 30, \"%d\", v);\n}\n\nextern \"C\" void *xmalloc(size_t sz);\n#define xfree free\n\n#define GC_ALLOC_BLOCK gcAllocBlock\n\n#ifndef POKY\n// This seems to degrade performance - probably due to cache size\n//#define GC_BLOCK_SIZE (1024 * 64)\n#endif\n\n#define PXT_HARD_FLOAT 1\n\n#endif\n",
1405
1405
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1406
1406
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace control {\n\n /**\n * Announce that an event happened to registered handlers.\n * @param src ID of the Component that generated the event\n * @param value Component specific code indicating the cause of the event.\n * @param mode optional definition of how the event should be processed after construction.\n */\n //% weight=21 blockGap=12 blockId=\"control_raise_event\"\n //% block=\"raise event|from %src|with value %value\" blockExternalInputs=1\n //% help=control/raise-event shim=control::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Allocates the next user notification event\n */\n //% help=control/allocate-notify-event shim=control::allocateNotifyEvent\n function allocateNotifyEvent(): int32;\n\n /**\n * Determine the version of system software currently running.\n */\n //% blockId=\"control_device_dal_version\" block=\"device dal version\"\n //% help=control/device-dal-version shim=control::deviceDalVersion\n function deviceDalVersion(): string;\n\n /** Write data to DMESG debugging buffer. */\n //% shim=control::dmesg\n function dmesg(s: string): void;\n\n /**\n * Determines if the USB has been enumerated.\n */\n //% shim=control::isUSBInitialized\n function isUSBInitialized(): boolean;\n}\ndeclare namespace serial {\n\n /** Send DMESG debug buffer over serial. */\n //% shim=serial::writeDmesg\n function writeDmesg(): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1437,7 +1437,7 @@ var pxtTargetBundle = {
1437
1437
  "platform.cpp": "#include \"pxt.h\"\n\n#include \"NRFLowLevelTimer.h\"\n\nnamespace pxt {\n\nstruct TimerConfig {\n uint8_t id;\n IRQn_Type irqn;\n NRF_TIMER_Type *addr;\n};\n\n#define DEF_TIM(n) \\\n { 0x10 + n, TIMER##n##_IRQn, NRF_TIMER##n }\n\nstatic const TimerConfig timers[] = {\n#ifdef NRF_TIMER0\n DEF_TIM(0),\n#endif\n#ifdef NRF_TIMER1\n DEF_TIM(1),\n#endif\n#ifdef NRF_TIMER2\n DEF_TIM(2),\n#endif\n#ifdef NRF_TIMER3\n DEF_TIM(3),\n#endif\n#ifdef NRF_TIMER4\n DEF_TIM(4),\n#endif\n#ifdef NRF_TIMER5\n DEF_TIM(5),\n#endif\n#ifdef NRF_TIMER6\n DEF_TIM(6),\n#endif\n {0, (IRQn_Type)0, 0}};\n\n#define DEF_TIMERS 0x11121013 // TIMER1 TIMER2 TIMER0 TIMER3\n\nstatic uint32_t usedTimers;\nstatic int timerIdx(uint8_t id) {\n for (unsigned i = 0; timers[i].id; i++) {\n if (id == timers[i].id)\n return i;\n }\n return -1;\n}\nLowLevelTimer *allocateTimer() {\n uint32_t timersToUse = getConfig(CFG_TIMERS_TO_USE, DEF_TIMERS);\n for (int shift = 24; shift >= 0; shift -= 8) {\n uint8_t tcId = (timersToUse >> shift) & 0xff;\n int idx = timerIdx(tcId);\n if (idx < 0 || (usedTimers & (1 << idx)))\n continue;\n auto dev = timers[idx].addr;\n if (dev->INTENSET) // any irqs enabled?\n continue; // then we won't allocate it\n usedTimers |= 1 << idx;\n DMESG(\"allocate TIMER%d\", tcId - 0x10);\n return new NRFLowLevelTimer(dev, timers[idx].irqn);\n }\n\n soft_panic(PANIC_OUT_OF_TIMERS);\n return NULL;\n}\n\nstatic void initRandomSeed() {\n int seed = 0xC0DA1;\n /*\n auto pinTemp = LOOKUP_PIN(TEMPERATURE);\n if (pinTemp)\n seed *= pinTemp->getAnalogValue();\n auto pinLight = LOOKUP_PIN(LIGHT);\n if (pinLight)\n seed *= pinLight->getAnalogValue();\n */\n seedRandom(seed);\n}\n\n#if defined(NRF52840) || defined(NRF52833)\n#define IS_3_3_V() ((NRF_UICR->REGOUT0 & 7) == 5)\n#else\n#define IS_3_3_V() 1\n#endif\n\nstatic void disableNFConPins() {\n // Ensure NFC pins are configured as GPIO. If not, update the non-volatile UICR.\n if (NRF_UICR->NFCPINS || !IS_3_3_V()) {\n DMESG(\"RESET UICR\\n\");\n // Enable Flash Writes\n NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);\n while (NRF_NVMC->READY == NVMC_READY_READY_Busy)\n ;\n\n // Configure PINS for GPIO use.\n if (NRF_UICR->NFCPINS)\n NRF_UICR->NFCPINS = 0;\n\n#if defined(NRF52840) || defined(NRF52833)\n // Set VDD to 3.3V\n if ((NRF_UICR->REGOUT0 & 7) != 5)\n NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~7) | 5;\n#endif\n\n // Disable Flash Writes\n NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);\n while (NRF_NVMC->READY == NVMC_READY_READY_Busy)\n ;\n\n // Reset, so the changes can take effect.\n NVIC_SystemReset();\n }\n}\n\nvoid deepSleep() {\n NRF_POWER->SYSTEMOFF = 1;\n}\n\nvoid platform_init() {\n#ifdef PXT_PROFILE\n CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;\n DWT->CYCCNT = 0;\n DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;\n#endif\n\n initRandomSeed();\n\n disableNFConPins(); // this is needed when P0_9 and P0_10 are to be used as regular pins\n\n /*\n if (*HF2_DBG_MAGIC_PTR == HF2_DBG_MAGIC_START) {\n *HF2_DBG_MAGIC_PTR = 0;\n // this will cause alignment fault at the first breakpoint\n globals[0] = (TValue)1;\n }\n */\n}\n\nint *getBootloaderConfigData() {\n#ifdef NRF52840\n auto p = (volatile uint32_t *)0x000fd800;\n if (p[0] == CFG_MAGIC0 && p[1] == CFG_MAGIC1)\n return (int *)p + 4;\n#endif\n\n return NULL;\n}\n\n} // namespace pxt\n\nvoid cpu_clock_init() {\n // missing in Codal\n}\n",
1438
1438
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n#include \"Image.h\"\n#include \"NRF52SPI.h\"\n#include \"NRF52I2C.h\"\n#include \"NRF52Pin.h\"\n#include \"NRF52PWM.h\"\n#include \"NRF52Serial.h\"\n#include \"NRF52PDM.h\"\n#include \"Timer.h\"\n#include \"MultiButton.h\"\n\n#define PAGE_SIZE 4096\n#define MIC_DEVICE NRF52PDM\n\n#if defined(NRF52840) || defined(NRF52833)\n#define DEV_NUM_PINS 48\n#else\n#define DEV_NUM_PINS 32\n#endif\n\n#define DEV_PWM_PINS 0x0000ffffffffULL // all pins are PWM pins it seems\n#define DEV_AIN_PINS 0x0000f000001fULL\n\n// Codal doesn't yet distinguish between PWM and AIN\n#define DEV_ANALOG_PINS (DEV_PWM_PINS | DEV_AIN_PINS)\n\n#define CODAL_PIN NRF52Pin\n#define CODAL_SPI NRF52SPI\n#define CODAL_I2C NRF52I2C\n#define CODAL_TIMER Timer\n#define CODAL_SERIAL NRF52Serial\n\n#define IMAGE_BITS 4\n\ntypedef uint8_t PinName;\n\n#define DEFAULT_NEOPIXEL_PIN P0_0\n\n#define PERF_NOW() (DWT->CYCCNT)\n#define PERF_NOW_SCALE 64\n\n// The parameters below needs tuning!\n\n/*\n * @param nominalValue The value (in SI units) of a nominal position.\n * @param nominalReading The raw reading from the sensor at the nominal position.\n * @param beta The Steinhart-Hart Beta constant for the device\n * @param seriesResistor The value (in ohms) of the resistor in series with the sensor.\n * @param zeroOffset Optional zero offset applied to all SI units (e.g. 273.15 for temperature\n * sensing in C vs Kelvin).\n */\n\n#define TEMPERATURE_NOMINAL_VALUE 25\n#define TEMPERATURE_NOMINAL_READING 10000\n#define TEMPERATURE_BETA 3380\n#define TEMPERATURE_SERIES_RESISTOR 10000\n#define TEMPERATURE_ZERO_OFFSET 273.5\n\n#define LIGHTSENSOR_SENSITIVITY 868 // codal has 912 now\n#define LIGHTSENSOR_LOW_THRESHOLD 128\n#define LIGHTSENSOR_HIGH_THRESHOLD 896\n\n\n#define P0_0 0\n#define P0_1 1\n#define P0_2 2\n#define P0_3 3\n#define P0_4 4\n#define P0_5 5\n#define P0_6 6\n#define P0_7 7\n#define P0_8 8\n#define P0_9 9\n#define P0_10 10\n#define P0_11 11\n#define P0_12 12\n#define P0_13 13\n#define P0_14 14\n#define P0_15 15\n#define P0_16 16\n#define P0_17 17\n#define P0_18 18\n#define P0_19 19\n#define P0_20 20\n#define P0_21 21\n#define P0_22 22\n#define P0_23 23\n#define P0_24 24\n#define P0_25 25\n#define P0_26 26\n#define P0_27 27\n#define P0_28 28\n#define P0_29 29\n#define P0_30 30\n#define P0_31 31\n#define P1_0 32\n#define P1_1 33\n#define P1_2 34\n#define P1_3 35\n#define P1_4 36\n#define P1_5 37\n#define P1_6 38\n#define P1_7 39\n#define P1_8 40\n#define P1_9 41\n#define P1_10 42\n#define P1_11 43\n#define P1_12 44\n#define P1_13 45\n#define P1_14 46\n#define P1_15 47\n#define P1_16 48\n#define P1_17 49\n#define P1_18 50\n#define P1_19 51\n#define P1_20 52\n#define P1_21 53\n#define P1_22 54\n#define P1_23 55\n#define P1_24 56\n#define P1_25 57\n#define P1_26 58\n#define P1_27 59\n#define P1_28 60\n#define P1_29 61\n#define P1_30 62\n#define P1_31 63\n\n#endif\n",
1439
1439
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#include \"CodalConfig.h\"\n#include \"CodalHeapAllocator.h\"\n#include \"CodalDevice.h\"\n#include \"CodalDmesg.h\"\n#include \"ErrorNo.h\"\n#include \"Timer.h\"\n#include \"Matrix4.h\"\n#include \"CodalCompat.h\"\n#include \"CodalComponent.h\"\n#include \"ManagedType.h\"\n#include \"Event.h\"\n#include \"NotifyEvents.h\"\n#include \"Button.h\"\n#include \"CodalFiber.h\"\n#include \"MessageBus.h\"\n#include \"MultiButton.h\"\n\nusing namespace codal;\n\n// codal::ManagedString compat\n#define MSTR(s) codal::ManagedString((s)->data, (s)->length)\n#define PSTR(s) mkString((s).toCharArray(), (s).length())\n\n#include \"pins.h\"\n\n#if CONFIG_ENABLED(DEVICE_USB)\n#include \"hf2.h\"\n#include \"hf2dbg.h\"\n#if CONFIG_ENABLED(DEVICE_MOUSE)\n#include \"HIDMouse.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\n#include \"HIDKeyboard.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\n#include \"HIDJoystick.h\"\n#endif\n#endif\n\n#define PXT_COMM_BASE 0x20002000 // 8k in\n\n// old codal compat\n#ifndef REAL_TIME_FUNC\n#define REAL_TIME_FUNC /* */\n#endif\n\nnamespace pxt {\n\n#if CONFIG_ENABLED(DEVICE_USB)\nextern CodalUSB usb;\nextern HF2 hf2;\n#if CONFIG_ENABLED(DEVICE_MOUSE)\nextern USBHIDMouse mouse;\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\nextern USBHIDKeyboard keyboard;\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\nextern USBHIDJoystick joystick;\n#endif\n#endif\n\n// Utility functions\nextern Event lastEvent;\nextern CODAL_TIMER devTimer;\nextern MessageBus devMessageBus;\nextern codal::CodalDevice device;\n\nvoid set_usb_strings(const char *uf2_info);\nextern void (*logJDFrame)(const uint8_t *data);\nextern void (*sendJDFrame)(const uint8_t *data);\n\nstatic inline void raiseEvent(int src, int val) {\n Event(src, val);\n}\n\n} // namespace pxt\n\nnamespace pins {\nclass CodalSPIProxy;\nclass CodalI2CProxy;\n} // namespace pins\n\ntypedef pins::CodalI2CProxy* I2C_;\ntypedef pins::CodalSPIProxy* SPI_;\n\nnamespace pxt {\ncodal::LowLevelTimer *allocateTimer();\n\n#ifdef CODAL_I2C\nCODAL_I2C* getI2C(DigitalInOutPin sda, DigitalInOutPin scl);\n#endif\nCODAL_SPI* getSPI(DigitalInOutPin mosi, DigitalInOutPin miso, DigitalInOutPin sck);\n#ifdef CODAL_JACDAC_WIRE_SERIAL\nLowLevelTimer* getJACDACTimer();\n#endif\nclass PressureButton;\nuint32_t readButtonMultiplexer(int bits);\nvoid disableButtonMultiplexer();\n}\n\nnamespace serial {\nclass CodalSerialDeviceProxy;\n}\n\ntypedef serial::CodalSerialDeviceProxy* SerialDevice;\n\nnamespace jacdac {\nclass JDProxyDriver;\n} // namespace network\n\ntypedef jacdac::JDProxyDriver* JacDacDriverStatus;\n\n#define DEVICE_ID_BUTTON_SLIDE 3000\n#define DEVICE_ID_MICROPHONE 3001\n#define DEVICE_ID_FIRST_BUTTON 4000\n#define DEVICE_ID_FIRST_TOUCHBUTTON 4100\n\n#define PXT_INTERNAL_KEY_UP 2050\n#define PXT_INTERNAL_KEY_DOWN 2051\n\n#endif\n",
1440
- "pxt.json": "{\n \"name\": \"core---nrf52\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1440
+ "pxt.json": "{\n \"name\": \"core---nrf52\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1441
1441
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include \"CodalDmesg.h\"\n#include \"CodalHeapAllocator.h\"\n\n#define PXT_CODAL 1\n\n#define itoa(a, b) codal::itoa(a, b)\n\n#define GC_GET_HEAP_SIZE() device_heap_size(0)\n#define GC_STACK_BASE DEVICE_STACK_BASE\n#define xmalloc device_malloc\n#define xfree device_free\n\n// on most devices we allocate the entire heap at once, so large allocs should work\n// if they don't you just get the regular out of memory instead of alloc too large\n#define GC_MAX_ALLOC_SIZE (128 * 1024)\n\n#endif\n",
1442
1442
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1443
1443
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace light {\n\n /**\n * Send a programmable light buffer to the specified digital pin\n * @param data The pin that the lights are connected to\n * @param clk the clock line if any\n * @param mode the color encoding mode\n * @param buf The buffer to send to the pin\n */\n //% shim=light::sendBuffer\n function sendBuffer(data: DigitalInOutPin, clk: DigitalInOutPin, mode: int32, buf: Buffer): void;\n}\ndeclare namespace control {\n\n /**\n * Determines if the USB has been enumerated.\n */\n //% shim=control::isUSBInitialized\n function isUSBInitialized(): boolean;\n}\ndeclare namespace pins {\n\n /**\n * Get a pin by configuration id (DAL.CFG_PIN...)\n */\n //% shim=pins::pinByCfg\n function pinByCfg(key: int32): DigitalInOutPin;\n\n /**\n * Create a new zero-initialized buffer.\n * @param size number of bytes in the buffer\n */\n //% shim=pins::createBuffer\n function createBuffer(size: int32): Buffer;\n\n /**\n * Get the duration of the last pulse in microseconds. This function should be called from a\n * ``onPulsed`` handler.\n */\n //% help=pins/pulse-duration blockGap=8\n //% blockId=pins_pulse_duration block=\"pulse duration (µs)\"\n //% weight=19 shim=pins::pulseDuration\n function pulseDuration(): int32;\n}\n\n\ndeclare interface AnalogInPin {\n /**\n * Read the connector value as analog, that is, as a value comprised between 0 and 1023.\n * @param name pin to write to\n */\n //% help=pins/analog-read weight=53\n //% blockId=device_get_analog_pin block=\"analog read|pin %name\" blockGap=\"8\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=AnalogInPinMethods::analogRead\n analogRead(): int32;\n}\n\n\ndeclare interface AnalogOutPin {\n /**\n * Set the connector value as analog. Value must be comprised between 0 and 1023.\n * @param name pin name to write to\n * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0\n */\n //% help=pins/analog-write weight=52\n //% blockId=device_set_analog_pin block=\"analog write|pin %name|to %value\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.min=0 value.max=1023 shim=AnalogOutPinMethods::analogWrite\n analogWrite(value: int32): void;\n}\n\n\ndeclare interface DigitalInOutPin {\n /**\n * Read a pin or connector as either 0 or 1\n * @param name pin to read from\n */\n //% help=pins/digital-read weight=61\n //% blockId=device_get_digital_pin block=\"digital read|pin %name\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalRead\n digitalRead(): boolean;\n\n /**\n * Set a pin or connector value to either 0 or 1.\n * @param name pin to write to\n * @param value value to set on the pin\n */\n //% help=pins/digital-write weight=60\n //% blockId=device_set_digital_pin block=\"digital write|pin %name|to %value=toggleHighLow\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalWrite\n digitalWrite(value: boolean): void;\n\n /**\n * Make this pin a digital input, and create events where the timestamp is the duration\n * that this pin was either ``high`` or ``low``.\n */\n //% help=pins/on-pulsed weight=16 blockGap=8\n //% blockId=pins_on_pulsed block=\"on|pin %pin|pulsed %pulse\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4\n //% deprecated=1 hidden=1 shim=DigitalInOutPinMethods::onPulsed\n onPulsed(pulse: PulseValue, body: () => void): void;\n\n /**\n * Register code to run when a pin event occurs. \n */\n //% help=pins/on-event weight=20 blockGap=8\n //% blockId=pinsonevent block=\"on|pin %pin|%event\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 shim=DigitalInOutPinMethods::onEvent\n onEvent(event: PinEvent, body: () => void): void;\n\n /**\n * Return the duration of a pulse in microseconds\n * @param name the pin which measures the pulse\n * @param value the value of the pulse (default high)\n * @param maximum duration in micro-seconds\n */\n //% blockId=\"pins_pulse_in\" block=\"pulse in (µs)|pin %name|pulsed %high||timeout %maxDuration (µs)\"\n //% weight=18 blockGap=8\n //% help=\"pins/pulse-in\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 maxDuration.defl=2000000 shim=DigitalInOutPinMethods::pulseIn\n pulseIn(value: PulseValue, maxDuration?: int32): int32;\n\n /**\n * Set the pull direction of this pin.\n * @param name pin to set the pull mode on\n * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone\n */\n //% help=pins/set-pull weight=17 blockGap=8\n //% blockId=device_set_pull block=\"set pull|pin %pin|to %pull\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::setPull\n setPull(pull: PinPullMode): void;\n}\n\n\ndeclare interface PwmPin {}\n\n\ndeclare interface PwmOnlyPin {\n /**\n * Set the Pulse-width modulation (PWM) period of the analog output. The period is in\n * **microseconds** or `1/1000` milliseconds.\n * If this pin is not configured as an analog output (using `analog write pin`), the operation has\n * no effect.\n * @param name analog pin to set period to\n * @param micros period in micro seconds. eg:20000\n */\n //% help=pins/analog-set-period weight=51\n //% blockId=device_set_analog_period block=\"analog set period|pin %pin|to (µs)%period\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::analogSetPeriod\n analogSetPeriod(period: int32): void;\n\n /**\n * Write a value to the servo to control the rotation of the shaft. On a standard servo, this will\n * set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous\n * rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one\n * direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).\n * @param name pin to write to\n * @param value angle or rotation speed\n */\n //% help=pins/servo-write weight=41 group=\"Servo\"\n //% blockId=device_set_servo_pin block=\"servo write|pin %name|to %value=protractorPicker\" blockGap=8\n //% parts=microservo trackArgs=0\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.defl=90 shim=PwmOnlyPinMethods::servoWrite\n servoWrite(value?: int32): void;\n\n /**\n * Set the pin for PWM analog output, make the period be 20 ms, and set the pulse width.\n * The pulse width is based on the value it is given **microseconds** or `1/1000` milliseconds.\n * @param name pin name\n * @param duration pulse duration in micro seconds, eg:1500\n */\n //% help=pins/servo-set-pulse weight=40 group=\"Servo\" blockGap=8\n //% blockId=device_set_servo_pulse block=\"servo set pulse|pin %value|to (µs) %duration\"\n //% parts=microservo blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::servoSetPulse\n servoSetPulse(duration: int32): void;\n\n /**\n * Indicates if the servo is running continuously\n */\n //% blockHidden=1 shim=PwmOnlyPinMethods::servoSetContinuous\n servoSetContinuous(continuous: boolean): void;\n}\ndeclare namespace control {\n\n /**\n * Announce that an event happened to registered handlers.\n * @param src ID of the MicroBit Component that generated the event\n * @param value Component specific code indicating the cause of the event.\n */\n //% weight=21 blockGap=12 blockId=\"control_raise_event\"\n //% help=control/raise-event\n //% block=\"raise event|from %src|with value %value\" blockExternalInputs=1 shim=control::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Determine the version of system software currently running.\n */\n //% blockId=\"control_device_dal_version\" block=\"device dal version\"\n //% help=control/device-dal-version shim=control::deviceDalVersion\n function deviceDalVersion(): string;\n\n /**\n * Allocates the next user notification event\n */\n //% help=control/allocate-notify-event shim=control::allocateNotifyEvent\n function allocateNotifyEvent(): int32;\n\n /** Write a message to DMESG debugging buffer. */\n //% shim=control::dmesg\n function dmesg(s: string): void;\n\n /** Write a message and value (pointer) to DMESG debugging buffer. */\n //% shim=control::dmesgPtr\n function dmesgPtr(str: string, ptr: Object): void;\n}\n\n\ndeclare interface I2C {\n /**\n * Read `size` bytes from a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::readBuffer\n readBuffer(address: int32, size: int32, repeat?: boolean): Buffer;\n\n /**\n * Write bytes to a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::writeBuffer\n writeBuffer(address: int32, buf: Buffer, repeat?: boolean): int32;\n}\ndeclare namespace pins {\n\n /**\n * Opens a Serial communication driver\n */\n //% help=pins/create-i2c\n //% parts=i2c shim=pins::createI2C\n function createI2C(sda: DigitalInOutPin, scl: DigitalInOutPin): I2C;\n}\ndeclare namespace pins {\n\n /**\n * Opens a SPI driver\n */\n //% help=pins/create-spi\n //% parts=spi shim=pins::createSPI\n function createSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin): SPI;\n\n /**\n * Opens a slave SPI driver\n */\n //% parts=spi shim=pins::createSlaveSPI\n function createSlaveSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin, csPin: DigitalInOutPin): SPI;\n}\n\n\ndeclare interface SPI {\n /**\n * Write to the SPI bus\n */\n //% shim=SPIMethods::write\n write(value: int32): int32;\n\n /**\n * Transfer buffers over the SPI bus\n */\n //% argsNullable shim=SPIMethods::transfer\n transfer(command: Buffer, response: Buffer): void;\n\n /**\n * Sets the SPI clock frequency\n */\n //% shim=SPIMethods::setFrequency\n setFrequency(frequency: int32): void;\n\n /**\n * Sets the SPI bus mode\n */\n //% shim=SPIMethods::setMode\n setMode(mode: int32): void;\n}\ndeclare namespace configStorage {\n\n /**\n * Puts an entry in the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n * @param value the data (max 32 characters)\n */\n //% shim=configStorage::setBuffer\n function setBuffer(key: string, value: Buffer): void;\n\n /**\n * Gets an entry from the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::getBuffer\n function getBuffer(key: string): Buffer;\n\n /**\n * Removes the key from local storage\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::removeItem\n function removeItem(key: string): void;\n\n /**\n * Clears the local storage\n */\n //% shim=configStorage::clear\n function clear(): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1478,7 +1478,7 @@ var pxtTargetBundle = {
1478
1478
  "platform.cpp": "#include \"pxt.h\"\n\n#include \"SAMDTCTimer.h\"\n#include \"SAMDTCCTimer.h\"\n#include \"light.h\"\n\nnamespace pxt {\n\nstruct TimerConfig {\n uint8_t id;\n uint8_t irq;\n uint8_t dmaovf;\n uint32_t addr;\n};\n\n#define DEF_TC(n) \\\n { 0x10 + n, TC##n##_IRQn, TC##n##_DMAC_ID_OVF, (uint32_t)TC##n }\n#ifdef SAMD21\n#define DEF_TCC(n) \\\n { 0x20 + n, TCC##n##_IRQn, TCC##n##_DMAC_ID_OVF, (uint32_t)TCC##n }\n#else\n#define DEF_TCC(n) \\\n { 0x20 + n, TCC##n##_0_IRQn, TCC##n##_DMAC_ID_OVF, (uint32_t)TCC##n }\n#endif\n\nstatic const TimerConfig timers[] = {\n#ifdef TC0\n DEF_TC(0),\n#endif\n#ifdef TC1\n DEF_TC(1),\n#endif\n#ifdef TC2\n DEF_TC(2),\n#endif\n#ifdef TC3\n DEF_TC(3),\n#endif\n#ifdef TC4\n DEF_TC(4),\n#endif\n#ifdef TC5\n DEF_TC(5),\n#endif\n\n#ifdef TCC0\n DEF_TCC(0),\n#endif\n#ifdef TCC1\n DEF_TCC(1),\n#endif\n#ifdef TCC2\n DEF_TCC(2),\n#endif\n\n {0, 0, 0, 0}};\n\n// Backlight:\n// Kitronik: PA6 TC1 (ch 0)\n// Adafruit: PA1 TC2 (ch 1)\n\n// TC3 is used by DAC on both D21 and D51\n// TCC0 and TC4 is used by IR\n// TCC0, TCC1, TC4 is used by PWM on CPX\n\n#ifdef SAMD21\n#define DEF_TIMERS 0x15222021 // TC5 TCC2 TCC0 TCC1\n#else\n#define DEF_TIMERS 0x10111200 // TC0 TC1 TC2\n#endif\n\nstatic uint32_t usedTimers;\nstatic int timerIdx(uint8_t id) {\n for (unsigned i = 0; timers[i].id; i++) {\n if (id == timers[i].id)\n return i;\n }\n return -1;\n}\nLowLevelTimer *allocateTimer() {\n uint32_t timersToUse = getConfig(CFG_TIMERS_TO_USE, DEF_TIMERS);\n uint8_t blTC = 0;\n // DAC hard-wired to TC3 right now\n uint8_t dacTC = 0x13;\n\n // if BL is on a known pin, don't use its PWM TC\n // this is a hack for legacy boards that don't have CFG_TIMERS_TO_USE\n auto blPin = PIN(DISPLAY_BL);\n if (blPin == PA01)\n blTC = 0x12;\n\n for (int shift = 24; shift >= 0; shift -= 8) {\n uint8_t tcId = (timersToUse >> shift) & 0xff;\n if (tcId == 0 || tcId == blTC || tcId == dacTC)\n continue;\n int idx = timerIdx(tcId);\n if (idx < 0 || (usedTimers & (1 << idx)))\n continue;\n LowLevelTimer *res;\n if (idx < 0x20) {\n Tc *tc = (Tc *)timers[idx].addr;\n if (tc->COUNT16.CTRLA.bit.ENABLE)\n continue;\n DMESG(\"allocate TC%d\", tcId & 0xf);\n res = new SAMDTCTimer(tc, timers[idx].irq);\n } else {\n Tcc *tcc = (Tcc *)timers[idx].addr;\n if (tcc->CTRLA.bit.ENABLE)\n continue;\n DMESG(\"allocate TCC%d\", tcId & 0xf);\n res = new SAMDTCCTimer(tcc, timers[idx].irq);\n }\n usedTimers |= 1 << idx;\n return res;\n }\n\n soft_panic(PANIC_OUT_OF_TIMERS);\n return NULL;\n}\n\nstatic void initRandomSeed() {\n int seed = 0xC0DA1;\n // TODO use TRNG\n seedRandom(seed);\n}\n\nvoid platformSendSerial(const char *data, int len) {}\n\n#ifdef SAMD21\nstatic void remapSwdPin(int pinCfg, int fallback) {\n int pinName = getConfig(pinCfg);\n if (pinName == PA30 || pinName == PA31) {\n if (getConfig(CFG_SWD_ENABLED, 0)) {\n linkPin(pinName, fallback);\n } else {\n PORT->Group[pinName / 32].PINCFG[pinName % 32].reg = (uint8_t)PORT_PINCFG_INEN;\n }\n }\n}\n\nstatic void initSwdPins() {\n remapSwdPin(CFG_PIN_NEOPIXEL, PIN(D0));\n remapSwdPin(CFG_PIN_RXLED, PIN(D1));\n remapSwdPin(CFG_PIN_SPEAKER_AMP, PIN(A2));\n}\n#else\nstatic void initSwdPins() {}\n#endif\n\nvoid platform_init() {\n initSwdPins();\n initRandomSeed();\n setSendToUART(platformSendSerial);\n light::clear();\n\n /*\n if (*HF2_DBG_MAGIC_PTR == HF2_DBG_MAGIC_START) {\n *HF2_DBG_MAGIC_PTR = 0;\n // this will cause alignment fault at the first breakpoint\n globals[0] = (TValue)1;\n }\n */\n}\n\nint *getBootloaderConfigData() {\n#ifdef SAMD51\n auto config_data = *(uint32_t *)(BOOTLOADER_END - 4 * 4);\n if (config_data && (config_data & 3) == 0 && config_data < BOOTLOADER_END) {\n auto p = (uint32_t *)config_data;\n if (p[0] == CFG_MAGIC0 && p[1] == CFG_MAGIC1)\n return (int *)p + 4;\n }\n#endif\n return NULL;\n}\n\n} // namespace pxt\n\nvoid cpu_clock_init() {}\n",
1479
1479
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n#include \"Image.h\"\n#include \"MultiButton.h\"\n#include \"ZPin.h\"\n#include \"Timer.h\"\n#include \"SAMDDAC.h\"\n#include \"ZSPI.h\"\n#include \"ZI2C.h\"\n#include \"ZSingleWireSerial.h\"\n#include \"SAMDNVM.h\"\n#include \"SAMDPDM.h\"\n#include \"SAMDSerial.h\"\n\n// cap touch not available on 51 yet\n#ifdef SAMD21\n#include \"CapTouchButton.h\"\n#endif\n\n#define MIC_DEVICE SAMD21PDM\n\n#ifdef SAMD21\n#define OUTPUT_BITS 10\n#else\n#define OUTPUT_BITS 12\n#endif\n\n#include \"pinmap.h\"\n\n#undef min\n#undef max\n\ntypedef int PinName;\n\n#define PAGE_SIZE 512\n\n#define BOOTLOADER_START 0x0\n\n#ifdef SAMD21\n#define BOOTLOADER_END 0x2000\n#endif\n\n#ifdef SAMD51\n#define BOOTLOADER_END 0x4000\n#endif\n\n#define USB_HANDOVER 0\n\n// if we ever want to support 100+ pin packages, need to add PC,PD ports and increase this to 128\n#ifdef SAMD51\n#define DEV_NUM_PINS 128\n#else\n#define DEV_NUM_PINS 64\n#endif\n\n#define IS_ANALOG_PIN(id) 1\n\n#define CODAL_PIN ZPin\n#define CODAL_TIMER Timer\n#define CODAL_SPI ZSPI\n#define CODAL_I2C ZI2C\n#define CODAL_JACDAC_WIRE_SERIAL codal::ZSingleWireSerial\n#define CODAL_SERIAL codal::SAMDSerial\n#define CODAL_DAC SAMDDAC\n\n#ifdef SAMD21\n#define CODAL_NVMCONTROLLER codal::SAMDNVM\n#endif\n\n#define PXT_74HC165 1\n\n#define IMAGE_BITS 4\n\n// The parameters below needs tuning!\n\n#define PA00 0\n#define PA01 1\n#define PA02 2\n#define PA03 3\n#define PA04 4\n#define PA05 5\n#define PA06 6\n#define PA07 7\n#define PA08 8\n#define PA09 9\n#define PA10 10\n#define PA11 11\n#define PA12 12\n#define PA13 13\n#define PA14 14\n#define PA15 15\n#define PA16 16\n#define PA17 17\n#define PA18 18\n#define PA19 19\n#define PA20 20\n#define PA21 21\n#define PA22 22\n#define PA23 23\n#define PA24 24\n#define PA25 25\n#define PA26 26\n#define PA27 27\n#define PA28 28\n#define PA29 29\n#define PA30 30\n#define PA31 31\n#define PB00 32\n#define PB01 33\n#define PB02 34\n#define PB03 35\n#define PB04 36\n#define PB05 37\n#define PB06 38\n#define PB07 39\n#define PB08 40\n#define PB09 41\n#define PB10 42\n#define PB11 43\n#define PB12 44\n#define PB13 45\n#define PB14 46\n#define PB15 47\n#define PB16 48\n#define PB17 49\n#define PB18 50\n#define PB19 51\n#define PB20 52\n#define PB21 53\n#define PB22 54\n#define PB23 55\n#define PB24 56\n#define PB25 57\n#define PB26 58\n#define PB27 59\n#define PB28 60\n#define PB29 61\n#define PB30 62\n#define PB31 63\n#define PC00 64\n#define PC01 65\n#define PC02 66\n#define PC03 67\n#define PC04 68\n#define PC05 69\n#define PC06 70\n#define PC07 71\n#define PC08 72\n#define PC09 73\n#define PC10 74\n#define PC11 75\n#define PC12 76\n#define PC13 77\n#define PC14 78\n#define PC15 79\n#define PC16 80\n#define PC17 81\n#define PC18 82\n#define PC19 83\n#define PC20 84\n#define PC21 85\n#define PC22 86\n#define PC23 87\n#define PC24 88\n#define PC25 89\n#define PC26 90\n#define PC27 91\n#define PC28 92\n#define PC29 93\n#define PC30 94\n#define PC31 95\n#define PD00 96\n#define PD01 97\n#define PD02 98\n#define PD03 99\n#define PD04 100\n#define PD05 101\n#define PD06 102\n#define PD07 103\n#define PD08 104\n#define PD09 105\n#define PD10 106\n#define PD11 107\n#define PD12 108\n#define PD13 109\n#define PD14 110\n#define PD15 111\n#define PD16 112\n#define PD17 113\n#define PD18 114\n#define PD19 115\n#define PD20 116\n#define PD21 117\n#define PD22 118\n#define PD23 119\n#define PD24 120\n#define PD25 121\n#define PD26 122\n#define PD27 123\n#define PD28 124\n#define PD29 125\n#define PD30 126\n#define PD31 127\n#endif\n",
1480
1480
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#include \"CodalConfig.h\"\n#include \"CodalHeapAllocator.h\"\n#include \"CodalDevice.h\"\n#include \"CodalDmesg.h\"\n#include \"ErrorNo.h\"\n#include \"Timer.h\"\n#include \"Matrix4.h\"\n#include \"CodalCompat.h\"\n#include \"CodalComponent.h\"\n#include \"ManagedType.h\"\n#include \"Event.h\"\n#include \"NotifyEvents.h\"\n#include \"Button.h\"\n#include \"CodalFiber.h\"\n#include \"MessageBus.h\"\n#include \"MultiButton.h\"\n\nusing namespace codal;\n\n// codal::ManagedString compat\n#define MSTR(s) codal::ManagedString((s)->data, (s)->length)\n#define PSTR(s) mkString((s).toCharArray(), (s).length())\n\n#include \"pins.h\"\n\n#if CONFIG_ENABLED(DEVICE_USB)\n#include \"hf2.h\"\n#include \"hf2dbg.h\"\n#if CONFIG_ENABLED(DEVICE_MOUSE)\n#include \"HIDMouse.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\n#include \"HIDKeyboard.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\n#include \"HIDJoystick.h\"\n#endif\n#endif\n\n#define PXT_COMM_BASE 0x20002000 // 8k in\n\n// old codal compat\n#ifndef REAL_TIME_FUNC\n#define REAL_TIME_FUNC /* */\n#endif\n\nnamespace pxt {\n\n#if CONFIG_ENABLED(DEVICE_USB)\nextern CodalUSB usb;\nextern HF2 hf2;\n#if CONFIG_ENABLED(DEVICE_MOUSE)\nextern USBHIDMouse mouse;\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\nextern USBHIDKeyboard keyboard;\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\nextern USBHIDJoystick joystick;\n#endif\n#endif\n\n// Utility functions\nextern Event lastEvent;\nextern CODAL_TIMER devTimer;\nextern MessageBus devMessageBus;\nextern codal::CodalDevice device;\n\nvoid set_usb_strings(const char *uf2_info);\nextern void (*logJDFrame)(const uint8_t *data);\nextern void (*sendJDFrame)(const uint8_t *data);\n\nstatic inline void raiseEvent(int src, int val) {\n Event(src, val);\n}\n\n} // namespace pxt\n\nnamespace pins {\nclass CodalSPIProxy;\nclass CodalI2CProxy;\n} // namespace pins\n\ntypedef pins::CodalI2CProxy* I2C_;\ntypedef pins::CodalSPIProxy* SPI_;\n\nnamespace pxt {\ncodal::LowLevelTimer *allocateTimer();\n\n#ifdef CODAL_I2C\nCODAL_I2C* getI2C(DigitalInOutPin sda, DigitalInOutPin scl);\n#endif\nCODAL_SPI* getSPI(DigitalInOutPin mosi, DigitalInOutPin miso, DigitalInOutPin sck);\n#ifdef CODAL_JACDAC_WIRE_SERIAL\nLowLevelTimer* getJACDACTimer();\n#endif\nclass PressureButton;\nuint32_t readButtonMultiplexer(int bits);\nvoid disableButtonMultiplexer();\n}\n\nnamespace serial {\nclass CodalSerialDeviceProxy;\n}\n\ntypedef serial::CodalSerialDeviceProxy* SerialDevice;\n\nnamespace jacdac {\nclass JDProxyDriver;\n} // namespace network\n\ntypedef jacdac::JDProxyDriver* JacDacDriverStatus;\n\n#define DEVICE_ID_BUTTON_SLIDE 3000\n#define DEVICE_ID_MICROPHONE 3001\n#define DEVICE_ID_FIRST_BUTTON 4000\n#define DEVICE_ID_FIRST_TOUCHBUTTON 4100\n\n#define PXT_INTERNAL_KEY_UP 2050\n#define PXT_INTERNAL_KEY_DOWN 2051\n\n#endif\n",
1481
- "pxt.json": "{\n \"name\": \"core---samd\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1481
+ "pxt.json": "{\n \"name\": \"core---samd\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1482
1482
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include \"CodalDmesg.h\"\n#include \"CodalHeapAllocator.h\"\n\n#define PXT_CODAL 1\n\n#define itoa(a, b) codal::itoa(a, b)\n\n#define GC_GET_HEAP_SIZE() device_heap_size(0)\n#define GC_STACK_BASE DEVICE_STACK_BASE\n#define xmalloc device_malloc\n#define xfree device_free\n\n// on most devices we allocate the entire heap at once, so large allocs should work\n// if they don't you just get the regular out of memory instead of alloc too large\n#define GC_MAX_ALLOC_SIZE (128 * 1024)\n\n#endif\n",
1483
1483
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1484
1484
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace light {\n\n /**\n * Send a programmable light buffer to the specified digital pin\n * @param data The pin that the lights are connected to\n * @param clk the clock line if any\n * @param mode the color encoding mode\n * @param buf The buffer to send to the pin\n */\n //% shim=light::sendBuffer\n function sendBuffer(data: DigitalInOutPin, clk: DigitalInOutPin, mode: int32, buf: Buffer): void;\n}\ndeclare namespace control {\n\n /**\n * Determines if the USB has been enumerated.\n */\n //% shim=control::isUSBInitialized\n function isUSBInitialized(): boolean;\n}\ndeclare namespace pins {\n\n /**\n * Get a pin by configuration id (DAL.CFG_PIN...)\n */\n //% shim=pins::pinByCfg\n function pinByCfg(key: int32): DigitalInOutPin;\n\n /**\n * Create a new zero-initialized buffer.\n * @param size number of bytes in the buffer\n */\n //% shim=pins::createBuffer\n function createBuffer(size: int32): Buffer;\n\n /**\n * Get the duration of the last pulse in microseconds. This function should be called from a\n * ``onPulsed`` handler.\n */\n //% help=pins/pulse-duration blockGap=8\n //% blockId=pins_pulse_duration block=\"pulse duration (µs)\"\n //% weight=19 shim=pins::pulseDuration\n function pulseDuration(): int32;\n}\n\n\ndeclare interface AnalogInPin {\n /**\n * Read the connector value as analog, that is, as a value comprised between 0 and 1023.\n * @param name pin to write to\n */\n //% help=pins/analog-read weight=53\n //% blockId=device_get_analog_pin block=\"analog read|pin %name\" blockGap=\"8\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=AnalogInPinMethods::analogRead\n analogRead(): int32;\n}\n\n\ndeclare interface AnalogOutPin {\n /**\n * Set the connector value as analog. Value must be comprised between 0 and 1023.\n * @param name pin name to write to\n * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0\n */\n //% help=pins/analog-write weight=52\n //% blockId=device_set_analog_pin block=\"analog write|pin %name|to %value\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.min=0 value.max=1023 shim=AnalogOutPinMethods::analogWrite\n analogWrite(value: int32): void;\n}\n\n\ndeclare interface DigitalInOutPin {\n /**\n * Read a pin or connector as either 0 or 1\n * @param name pin to read from\n */\n //% help=pins/digital-read weight=61\n //% blockId=device_get_digital_pin block=\"digital read|pin %name\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalRead\n digitalRead(): boolean;\n\n /**\n * Set a pin or connector value to either 0 or 1.\n * @param name pin to write to\n * @param value value to set on the pin\n */\n //% help=pins/digital-write weight=60\n //% blockId=device_set_digital_pin block=\"digital write|pin %name|to %value=toggleHighLow\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalWrite\n digitalWrite(value: boolean): void;\n\n /**\n * Make this pin a digital input, and create events where the timestamp is the duration\n * that this pin was either ``high`` or ``low``.\n */\n //% help=pins/on-pulsed weight=16 blockGap=8\n //% blockId=pins_on_pulsed block=\"on|pin %pin|pulsed %pulse\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4\n //% deprecated=1 hidden=1 shim=DigitalInOutPinMethods::onPulsed\n onPulsed(pulse: PulseValue, body: () => void): void;\n\n /**\n * Register code to run when a pin event occurs. \n */\n //% help=pins/on-event weight=20 blockGap=8\n //% blockId=pinsonevent block=\"on|pin %pin|%event\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 shim=DigitalInOutPinMethods::onEvent\n onEvent(event: PinEvent, body: () => void): void;\n\n /**\n * Return the duration of a pulse in microseconds\n * @param name the pin which measures the pulse\n * @param value the value of the pulse (default high)\n * @param maximum duration in micro-seconds\n */\n //% blockId=\"pins_pulse_in\" block=\"pulse in (µs)|pin %name|pulsed %high||timeout %maxDuration (µs)\"\n //% weight=18 blockGap=8\n //% help=\"pins/pulse-in\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 maxDuration.defl=2000000 shim=DigitalInOutPinMethods::pulseIn\n pulseIn(value: PulseValue, maxDuration?: int32): int32;\n\n /**\n * Set the pull direction of this pin.\n * @param name pin to set the pull mode on\n * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone\n */\n //% help=pins/set-pull weight=17 blockGap=8\n //% blockId=device_set_pull block=\"set pull|pin %pin|to %pull\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::setPull\n setPull(pull: PinPullMode): void;\n}\n\n\ndeclare interface PwmPin {}\n\n\ndeclare interface PwmOnlyPin {\n /**\n * Set the Pulse-width modulation (PWM) period of the analog output. The period is in\n * **microseconds** or `1/1000` milliseconds.\n * If this pin is not configured as an analog output (using `analog write pin`), the operation has\n * no effect.\n * @param name analog pin to set period to\n * @param micros period in micro seconds. eg:20000\n */\n //% help=pins/analog-set-period weight=51\n //% blockId=device_set_analog_period block=\"analog set period|pin %pin|to (µs)%period\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::analogSetPeriod\n analogSetPeriod(period: int32): void;\n\n /**\n * Write a value to the servo to control the rotation of the shaft. On a standard servo, this will\n * set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous\n * rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one\n * direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).\n * @param name pin to write to\n * @param value angle or rotation speed\n */\n //% help=pins/servo-write weight=41 group=\"Servo\"\n //% blockId=device_set_servo_pin block=\"servo write|pin %name|to %value=protractorPicker\" blockGap=8\n //% parts=microservo trackArgs=0\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.defl=90 shim=PwmOnlyPinMethods::servoWrite\n servoWrite(value?: int32): void;\n\n /**\n * Set the pin for PWM analog output, make the period be 20 ms, and set the pulse width.\n * The pulse width is based on the value it is given **microseconds** or `1/1000` milliseconds.\n * @param name pin name\n * @param duration pulse duration in micro seconds, eg:1500\n */\n //% help=pins/servo-set-pulse weight=40 group=\"Servo\" blockGap=8\n //% blockId=device_set_servo_pulse block=\"servo set pulse|pin %value|to (µs) %duration\"\n //% parts=microservo blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::servoSetPulse\n servoSetPulse(duration: int32): void;\n\n /**\n * Indicates if the servo is running continuously\n */\n //% blockHidden=1 shim=PwmOnlyPinMethods::servoSetContinuous\n servoSetContinuous(continuous: boolean): void;\n}\ndeclare namespace control {\n\n /**\n * Announce that an event happened to registered handlers.\n * @param src ID of the MicroBit Component that generated the event\n * @param value Component specific code indicating the cause of the event.\n */\n //% weight=21 blockGap=12 blockId=\"control_raise_event\"\n //% help=control/raise-event\n //% block=\"raise event|from %src|with value %value\" blockExternalInputs=1 shim=control::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Determine the version of system software currently running.\n */\n //% blockId=\"control_device_dal_version\" block=\"device dal version\"\n //% help=control/device-dal-version shim=control::deviceDalVersion\n function deviceDalVersion(): string;\n\n /**\n * Allocates the next user notification event\n */\n //% help=control/allocate-notify-event shim=control::allocateNotifyEvent\n function allocateNotifyEvent(): int32;\n\n /** Write a message to DMESG debugging buffer. */\n //% shim=control::dmesg\n function dmesg(s: string): void;\n\n /** Write a message and value (pointer) to DMESG debugging buffer. */\n //% shim=control::dmesgPtr\n function dmesgPtr(str: string, ptr: Object): void;\n}\n\n\ndeclare interface I2C {\n /**\n * Read `size` bytes from a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::readBuffer\n readBuffer(address: int32, size: int32, repeat?: boolean): Buffer;\n\n /**\n * Write bytes to a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::writeBuffer\n writeBuffer(address: int32, buf: Buffer, repeat?: boolean): int32;\n}\ndeclare namespace pins {\n\n /**\n * Opens a Serial communication driver\n */\n //% help=pins/create-i2c\n //% parts=i2c shim=pins::createI2C\n function createI2C(sda: DigitalInOutPin, scl: DigitalInOutPin): I2C;\n}\ndeclare namespace pins {\n\n /**\n * Opens a SPI driver\n */\n //% help=pins/create-spi\n //% parts=spi shim=pins::createSPI\n function createSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin): SPI;\n\n /**\n * Opens a slave SPI driver\n */\n //% parts=spi shim=pins::createSlaveSPI\n function createSlaveSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin, csPin: DigitalInOutPin): SPI;\n}\n\n\ndeclare interface SPI {\n /**\n * Write to the SPI bus\n */\n //% shim=SPIMethods::write\n write(value: int32): int32;\n\n /**\n * Transfer buffers over the SPI bus\n */\n //% argsNullable shim=SPIMethods::transfer\n transfer(command: Buffer, response: Buffer): void;\n\n /**\n * Sets the SPI clock frequency\n */\n //% shim=SPIMethods::setFrequency\n setFrequency(frequency: int32): void;\n\n /**\n * Sets the SPI bus mode\n */\n //% shim=SPIMethods::setMode\n setMode(mode: int32): void;\n}\ndeclare namespace configStorage {\n\n /**\n * Puts an entry in the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n * @param value the data (max 32 characters)\n */\n //% shim=configStorage::setBuffer\n function setBuffer(key: string, value: Buffer): void;\n\n /**\n * Gets an entry from the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::getBuffer\n function getBuffer(key: string): Buffer;\n\n /**\n * Removes the key from local storage\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::removeItem\n function removeItem(key: string): void;\n\n /**\n * Clears the local storage\n */\n //% shim=configStorage::clear\n function clear(): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1519,7 +1519,7 @@ var pxtTargetBundle = {
1519
1519
  "platform.cpp": "#include \"pxt.h\"\n#include \"STMLowLevelTimer.h\"\n#include \"Accelerometer.h\"\n#include \"light.h\"\n\nnamespace pxt {\n\nstruct TimerConfig {\n uint8_t id;\n uint8_t irqn;\n TIM_TypeDef *addr;\n};\n\n#define TIM1_IRQn TIM1_CC_IRQn\n#ifdef STM32F4\n#define TIM9_IRQn TIM1_BRK_TIM9_IRQn\n#define TIM10_IRQn TIM1_UP_TIM10_IRQn\n#define TIM11_IRQn TIM1_TRG_COM_TIM11_IRQn\n#endif\n\n#define DEF_TIM(n) \\\n { 0x10 + n, TIM##n##_IRQn, TIM##n }\n\nstatic const TimerConfig timers[] = {\n#ifdef TIM1\n DEF_TIM(1),\n#endif\n#ifdef TIM2\n DEF_TIM(2),\n#endif\n#ifdef TIM3\n DEF_TIM(3),\n#endif\n#ifdef TIM4\n DEF_TIM(4),\n#endif\n#ifdef TIM5\n DEF_TIM(5),\n#endif\n#ifdef TIM6\n DEF_TIM(6),\n#endif\n#ifdef TIM7\n DEF_TIM(7),\n#endif\n#ifdef TIM8\n DEF_TIM(8),\n#endif\n#ifdef TIM9\n DEF_TIM(9),\n#endif\n#ifdef TIM10\n DEF_TIM(10),\n#endif\n#ifdef TIM11\n DEF_TIM(11),\n#endif\n#ifdef TIM12\n DEF_TIM(12),\n#endif\n#ifdef TIM13\n DEF_TIM(13),\n#endif\n#ifdef TIM14\n DEF_TIM(14),\n#endif\n#ifdef TIM15\n DEF_TIM(15),\n#endif\n{0,0,0}\n};\n\n#ifdef STM32F1\n#define DEF_TIMERS 0x14120000 // TIM4 TIM2\n#else\n#define DEF_TIMERS 0x15120000 // TIM5 TIM2\n#endif\n\nstatic uint32_t usedTimers;\nstatic int timerIdx(uint8_t id) {\n for (unsigned i = 0; timers[i].id; i++) {\n if (id == timers[i].id)\n return i;\n }\n return -1;\n}\nLowLevelTimer *allocateTimer() {\n uint32_t timersToUse = getConfig(CFG_TIMERS_TO_USE, DEF_TIMERS);\n for (int shift = 24; shift >= 0; shift -= 8) {\n uint8_t tcId = (timersToUse >> shift) & 0xff;\n int idx = timerIdx(tcId);\n if (idx < 0 || (usedTimers & (1 << idx)))\n continue;\n auto dev = timers[idx].addr;\n if (dev->CR1 & TIM_CR1_CEN)\n continue;\n usedTimers |= 1 << idx;\n DMESG(\"allocate TIM%d\", tcId - 0x10);\n return new STMLowLevelTimer(dev, timers[idx].irqn);\n }\n\n soft_panic(PANIC_OUT_OF_TIMERS);\n return NULL;\n}\n\n\nvoid initAccelRandom();\n#ifdef STM32F4\nextern \"C\" void apply_clock_init(RCC_OscInitTypeDef *oscInit, RCC_ClkInitTypeDef *clkConfig,\n uint32_t flashLatency) {\n\n int mhz = getConfig(CFG_CPU_MHZ, 84);\n\n if (mhz >= 216) {\n oscInit->PLL.PLLN = 432;\n oscInit->PLL.PLLP = RCC_PLLP_DIV2;\n oscInit->PLL.PLLQ = 9;\n flashLatency = FLASH_LATENCY_6;\n } else if (mhz >= 192) {\n oscInit->PLL.PLLN = 384;\n oscInit->PLL.PLLP = RCC_PLLP_DIV2;\n oscInit->PLL.PLLQ = 8;\n flashLatency = FLASH_LATENCY_6;\n } else if (mhz >= 168) {\n oscInit->PLL.PLLN = 336;\n oscInit->PLL.PLLP = RCC_PLLP_DIV2;\n oscInit->PLL.PLLQ = 7;\n flashLatency = FLASH_LATENCY_5;\n } else if (mhz >= 144) {\n oscInit->PLL.PLLN = 288;\n oscInit->PLL.PLLP = RCC_PLLP_DIV2;\n oscInit->PLL.PLLQ = 6;\n flashLatency = FLASH_LATENCY_5;\n } else if (mhz >= 108) {\n oscInit->PLL.PLLN = 432;\n oscInit->PLL.PLLP = RCC_PLLP_DIV4;\n oscInit->PLL.PLLQ = 9;\n flashLatency = FLASH_LATENCY_4;\n } else if (mhz >= 96) {\n oscInit->PLL.PLLN = 384;\n oscInit->PLL.PLLP = RCC_PLLP_DIV4;\n oscInit->PLL.PLLQ = 8;\n flashLatency = FLASH_LATENCY_3;\n } else if (mhz >= 84) {\n // this is the default from codal\n oscInit->PLL.PLLN = 336;\n oscInit->PLL.PLLP = RCC_PLLP_DIV4;\n oscInit->PLL.PLLQ = 7;\n flashLatency = FLASH_LATENCY_2;\n } else {\n soft_panic(PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR);\n }\n\n DMESG(\"CPU clock: %dMHz -> %dMHz\", mhz,\n oscInit->PLL.PLLN / (oscInit->PLL.PLLP == RCC_PLLP_DIV4 ? 4 : 2));\n\n if (mhz > 108) {\n clkConfig->APB1CLKDivider = RCC_HCLK_DIV4;\n clkConfig->APB2CLKDivider = RCC_HCLK_DIV2;\n } else {\n clkConfig->APB1CLKDivider = RCC_HCLK_DIV2;\n clkConfig->APB2CLKDivider = RCC_HCLK_DIV1;\n }\n\n HAL_RCC_OscConfig(oscInit);\n HAL_RCC_ClockConfig(clkConfig, flashLatency);\n}\n#endif\n\n// Disable seeding random from accelerometer. We now store random\n// seed in internal flash, so it's different on every reset, and\n// accelerometer sometimes have bugs, so better not enable them unless\n// requested.\nstatic void initRandomSeed() {\n#if 0\n if (getConfig(CFG_ACCELEROMETER_TYPE, -1) != -1) {\n initAccelRandom();\n }\n#endif\n}\n\nstatic void set_if_present(int cfg, int val) {\n auto snd = pxt::lookupPinCfg(cfg);\n if (snd)\n snd->setDigitalValue(val);\n}\n\n//%\nvoid deepSleep() {\n // this in particular puts accelerometer to sleep, which the bootloader\n // doesn't do\n CodalComponent::setAllSleep(true);\n\n#ifdef STM32F4\n // ask bootloader to do the deep sleeping\n QUICK_BOOT(1);\n RTC->BKP1R = 0x10b37889;\n NVIC_SystemReset();\n#endif\n}\n\nvoid platformSendSerial(const char *data, int len) {\n /*\n if (!serial) {\n serial = new codal::_mbed::Serial(USBTX, NC);\n serial->baud(9600);\n }\n serial->send((uint8_t*)data, len);\n */\n}\n\nvoid platform_init() {\n initRandomSeed();\n setSendToUART(platformSendSerial);\n light::clear();\n\n // make sure sound doesn't draw power before enabled\n set_if_present(CFG_PIN_JACK_SND, 0);\n set_if_present(CFG_PIN_JACK_HPEN, 0);\n set_if_present(CFG_PIN_JACK_BZEN, 1);\n\n /*\n if (*HF2_DBG_MAGIC_PTR == HF2_DBG_MAGIC_START) {\n *HF2_DBG_MAGIC_PTR = 0;\n // this will cause alignment fault at the first breakpoint\n globals[0] = (TValue)1;\n }\n */\n}\n\nint *getBootloaderConfigData() {\n#ifdef STM32F4\n auto config_data = (uint32_t)(UF2_BINFO->configValues);\n if (config_data && (config_data & 3) == 0) {\n auto p = (uint32_t *)config_data - 4;\n if (p[0] == CFG_MAGIC0 && p[1] == CFG_MAGIC1)\n return (int *)p + 4;\n }\n#endif\n\n return NULL;\n}\n\n#define STM32_UUID ((uint32_t *)0x1FFF7A10)\n\nstatic void writeHex(char *buf, uint32_t n) {\n int i = 0;\n int sh = 28;\n while (sh >= 0) {\n int d = (n >> sh) & 0xf;\n buf[i++] = d > 9 ? 'A' + d - 10 : '0' + d;\n sh -= 4;\n }\n buf[i] = 0;\n}\n\nvoid platform_usb_init() {\n#if CONFIG_ENABLED(DEVICE_USB)\n static char serial_number[25];\n\n writeHex(serial_number, STM32_UUID[0]);\n writeHex(serial_number + 8, STM32_UUID[1]);\n writeHex(serial_number + 16, STM32_UUID[2]);\n\n usb.stringDescriptors[2] = serial_number;\n#endif\n}\n\n} // namespace pxt\n\nvoid cpu_clock_init() {}\n",
1520
1520
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n#include \"Image.h\"\n#include \"MultiButton.h\"\n#include \"ZPin.h\"\n#include \"Timer.h\"\n#include \"ZSPI.h\"\n#include \"ZI2C.h\"\n#include \"ZSingleWireSerial.h\"\n\n#include \"pinmap.h\"\n\n#define BOOTLOADER_START 0x08000000\n#define BOOTLOADER_END 0x08008000\n\n#ifdef STM32F4\n#define SETTINGS_MAGIC_0 0x10476643\n#define SETTINGS_MAGIC_1 0x2e9a5026\n\nstruct F4_Settings {\n uint32_t magic0;\n uint32_t magic1;\n int *configValues;\n uint32_t hseValue;\n const char *info_uf2;\n const char *manufacturer;\n const char *device;\n uint32_t reserved[16 - 7];\n};\n\n#define UF2_BINFO ((F4_Settings *)(BOOTLOADER_END - sizeof(F4_Settings)))\n#define UF2_INFO_TXT UF2_BINFO->info_uf2\n#define USB_HANDOVER 0\n\n#define BOOT_RTC_SIGNATURE 0x71a21877\n#define APP_RTC_SIGNATURE 0x24a22d12\n#define HF2_RTC_SIGNATURE 0x39a63a78\n#define QUICK_BOOT(v) \\\n do { \\\n RTC->BKP0R = v ? APP_RTC_SIGNATURE : HF2_RTC_SIGNATURE; \\\n } while (0)\n#endif\n\n#define PAGE_SIZE 1024 // not really\n\n#define DEV_NUM_PINS 64\n\n#ifdef STM32F1\n#define DEV_PWM_PINS 0b111100000011101100001110111000111111001110LL\n#else\n#define DEV_PWM_PINS 0b111100000011100111111110111000111111101111LL\n#endif\n\n// CCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA\n// fedcba9876543210fedcba9876543210fedcba9876543210\n#define DEV_AIN_PINS 0b000011111100000000000000110000000011111111LL\n\n// Codal doesn't yet distinguish between PWM and AIN\n#define DEV_ANALOG_PINS (DEV_PWM_PINS | DEV_AIN_PINS)\n\n#define CODAL_PIN ZPin\n#define CODAL_TIMER Timer\n#define CODAL_SPI ZSPI\n#define CODAL_I2C ZI2C\n#define CODAL_JACDAC_WIRE_SERIAL codal::ZSingleWireSerial\n\n#define PERF_NOW() (TIM5->CNT)\n\n#define IMAGE_BITS 4\n\n\n// The parameters below needs tuning!\n\n#ifdef JUST_FOR_DAL_D_TS_CPP_WILL_IGNORE\n#define PA_0 0x00\n#define PA_1 0x01\n#define PA_2 0x02\n#define PA_3 0x03\n#define PA_4 0x04\n#define PA_5 0x05\n#define PA_6 0x06\n#define PA_7 0x07\n#define PA_8 0x08\n#define PA_9 0x09\n#define PA_10 0x0A\n#define PA_11 0x0B\n#define PA_12 0x0C\n#define PA_13 0x0D\n#define PA_14 0x0E\n#define PA_15 0x0F\n\n#define PB_0 0x10\n#define PB_1 0x11\n#define PB_2 0x12\n#define PB_3 0x13\n#define PB_4 0x14\n#define PB_5 0x15\n#define PB_6 0x16\n#define PB_7 0x17\n#define PB_8 0x18\n#define PB_9 0x19\n#define PB_10 0x1A\n#define PB_11 0x1B\n#define PB_12 0x1C\n#define PB_13 0x1D\n#define PB_14 0x1E\n#define PB_15 0x1F\n\n#define PC_0 0x20\n#define PC_1 0x21\n#define PC_2 0x22\n#define PC_3 0x23\n#define PC_4 0x24\n#define PC_5 0x25\n#define PC_6 0x26\n#define PC_7 0x27\n#define PC_8 0x28\n#define PC_9 0x29\n#define PC_10 0x2A\n#define PC_11 0x2B\n#define PC_12 0x2C\n#define PC_13 0x2D\n#define PC_14 0x2E\n#define PC_15 0x2F\n\n#define PD_0 0x30\n#define PD_1 0x31\n#define PD_2 0x32\n#define PD_3 0x33\n#define PD_4 0x34\n#define PD_5 0x35\n#define PD_6 0x36\n#define PD_7 0x37\n#define PD_8 0x38\n#define PD_9 0x39\n#define PD_10 0x3A\n#define PD_11 0x3B\n#define PD_12 0x3C\n#define PD_13 0x3D\n#define PD_14 0x3E\n#define PD_15 0x3F\n#endif\n\n#endif",
1521
1521
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#include \"CodalConfig.h\"\n#include \"CodalHeapAllocator.h\"\n#include \"CodalDevice.h\"\n#include \"CodalDmesg.h\"\n#include \"ErrorNo.h\"\n#include \"Timer.h\"\n#include \"Matrix4.h\"\n#include \"CodalCompat.h\"\n#include \"CodalComponent.h\"\n#include \"ManagedType.h\"\n#include \"Event.h\"\n#include \"NotifyEvents.h\"\n#include \"Button.h\"\n#include \"CodalFiber.h\"\n#include \"MessageBus.h\"\n#include \"MultiButton.h\"\n\nusing namespace codal;\n\n// codal::ManagedString compat\n#define MSTR(s) codal::ManagedString((s)->data, (s)->length)\n#define PSTR(s) mkString((s).toCharArray(), (s).length())\n\n#include \"pins.h\"\n\n#if CONFIG_ENABLED(DEVICE_USB)\n#include \"hf2.h\"\n#include \"hf2dbg.h\"\n#if CONFIG_ENABLED(DEVICE_MOUSE)\n#include \"HIDMouse.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\n#include \"HIDKeyboard.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\n#include \"HIDJoystick.h\"\n#endif\n#endif\n\n#define PXT_COMM_BASE 0x20002000 // 8k in\n\n// old codal compat\n#ifndef REAL_TIME_FUNC\n#define REAL_TIME_FUNC /* */\n#endif\n\nnamespace pxt {\n\n#if CONFIG_ENABLED(DEVICE_USB)\nextern CodalUSB usb;\nextern HF2 hf2;\n#if CONFIG_ENABLED(DEVICE_MOUSE)\nextern USBHIDMouse mouse;\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\nextern USBHIDKeyboard keyboard;\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\nextern USBHIDJoystick joystick;\n#endif\n#endif\n\n// Utility functions\nextern Event lastEvent;\nextern CODAL_TIMER devTimer;\nextern MessageBus devMessageBus;\nextern codal::CodalDevice device;\n\nvoid set_usb_strings(const char *uf2_info);\nextern void (*logJDFrame)(const uint8_t *data);\nextern void (*sendJDFrame)(const uint8_t *data);\n\nstatic inline void raiseEvent(int src, int val) {\n Event(src, val);\n}\n\n} // namespace pxt\n\nnamespace pins {\nclass CodalSPIProxy;\nclass CodalI2CProxy;\n} // namespace pins\n\ntypedef pins::CodalI2CProxy* I2C_;\ntypedef pins::CodalSPIProxy* SPI_;\n\nnamespace pxt {\ncodal::LowLevelTimer *allocateTimer();\n\n#ifdef CODAL_I2C\nCODAL_I2C* getI2C(DigitalInOutPin sda, DigitalInOutPin scl);\n#endif\nCODAL_SPI* getSPI(DigitalInOutPin mosi, DigitalInOutPin miso, DigitalInOutPin sck);\n#ifdef CODAL_JACDAC_WIRE_SERIAL\nLowLevelTimer* getJACDACTimer();\n#endif\nclass PressureButton;\nuint32_t readButtonMultiplexer(int bits);\nvoid disableButtonMultiplexer();\n}\n\nnamespace serial {\nclass CodalSerialDeviceProxy;\n}\n\ntypedef serial::CodalSerialDeviceProxy* SerialDevice;\n\nnamespace jacdac {\nclass JDProxyDriver;\n} // namespace network\n\ntypedef jacdac::JDProxyDriver* JacDacDriverStatus;\n\n#define DEVICE_ID_BUTTON_SLIDE 3000\n#define DEVICE_ID_MICROPHONE 3001\n#define DEVICE_ID_FIRST_BUTTON 4000\n#define DEVICE_ID_FIRST_TOUCHBUTTON 4100\n\n#define PXT_INTERNAL_KEY_UP 2050\n#define PXT_INTERNAL_KEY_DOWN 2051\n\n#endif\n",
1522
- "pxt.json": "{\n \"name\": \"core---stm32\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1522
+ "pxt.json": "{\n \"name\": \"core---stm32\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1523
1523
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include \"CodalDmesg.h\"\n#include \"CodalHeapAllocator.h\"\n\n#define PXT_CODAL 1\n\n#define itoa(a, b) codal::itoa(a, b)\n\n#define GC_GET_HEAP_SIZE() device_heap_size(0)\n#define GC_STACK_BASE DEVICE_STACK_BASE\n#define xmalloc device_malloc\n#define xfree device_free\n\n// on most devices we allocate the entire heap at once, so large allocs should work\n// if they don't you just get the regular out of memory instead of alloc too large\n#define GC_MAX_ALLOC_SIZE (128 * 1024)\n\n#endif\n",
1524
1524
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1525
1525
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace light {\n\n /**\n * Send a programmable light buffer to the specified digital pin\n * @param data The pin that the lights are connected to\n * @param clk the clock line if any\n * @param mode the color encoding mode\n * @param buf The buffer to send to the pin\n */\n //% shim=light::sendBuffer\n function sendBuffer(data: DigitalInOutPin, clk: DigitalInOutPin, mode: int32, buf: Buffer): void;\n}\ndeclare namespace control {\n\n /**\n * Determines if the USB has been enumerated.\n */\n //% shim=control::isUSBInitialized\n function isUSBInitialized(): boolean;\n}\ndeclare namespace pins {\n\n /**\n * Get a pin by configuration id (DAL.CFG_PIN...)\n */\n //% shim=pins::pinByCfg\n function pinByCfg(key: int32): DigitalInOutPin;\n\n /**\n * Create a new zero-initialized buffer.\n * @param size number of bytes in the buffer\n */\n //% shim=pins::createBuffer\n function createBuffer(size: int32): Buffer;\n\n /**\n * Get the duration of the last pulse in microseconds. This function should be called from a\n * ``onPulsed`` handler.\n */\n //% help=pins/pulse-duration blockGap=8\n //% blockId=pins_pulse_duration block=\"pulse duration (µs)\"\n //% weight=19 shim=pins::pulseDuration\n function pulseDuration(): int32;\n}\n\n\ndeclare interface AnalogInPin {\n /**\n * Read the connector value as analog, that is, as a value comprised between 0 and 1023.\n * @param name pin to write to\n */\n //% help=pins/analog-read weight=53\n //% blockId=device_get_analog_pin block=\"analog read|pin %name\" blockGap=\"8\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=AnalogInPinMethods::analogRead\n analogRead(): int32;\n}\n\n\ndeclare interface AnalogOutPin {\n /**\n * Set the connector value as analog. Value must be comprised between 0 and 1023.\n * @param name pin name to write to\n * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0\n */\n //% help=pins/analog-write weight=52\n //% blockId=device_set_analog_pin block=\"analog write|pin %name|to %value\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.min=0 value.max=1023 shim=AnalogOutPinMethods::analogWrite\n analogWrite(value: int32): void;\n}\n\n\ndeclare interface DigitalInOutPin {\n /**\n * Read a pin or connector as either 0 or 1\n * @param name pin to read from\n */\n //% help=pins/digital-read weight=61\n //% blockId=device_get_digital_pin block=\"digital read|pin %name\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalRead\n digitalRead(): boolean;\n\n /**\n * Set a pin or connector value to either 0 or 1.\n * @param name pin to write to\n * @param value value to set on the pin\n */\n //% help=pins/digital-write weight=60\n //% blockId=device_set_digital_pin block=\"digital write|pin %name|to %value=toggleHighLow\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalWrite\n digitalWrite(value: boolean): void;\n\n /**\n * Make this pin a digital input, and create events where the timestamp is the duration\n * that this pin was either ``high`` or ``low``.\n */\n //% help=pins/on-pulsed weight=16 blockGap=8\n //% blockId=pins_on_pulsed block=\"on|pin %pin|pulsed %pulse\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4\n //% deprecated=1 hidden=1 shim=DigitalInOutPinMethods::onPulsed\n onPulsed(pulse: PulseValue, body: () => void): void;\n\n /**\n * Register code to run when a pin event occurs. \n */\n //% help=pins/on-event weight=20 blockGap=8\n //% blockId=pinsonevent block=\"on|pin %pin|%event\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 shim=DigitalInOutPinMethods::onEvent\n onEvent(event: PinEvent, body: () => void): void;\n\n /**\n * Return the duration of a pulse in microseconds\n * @param name the pin which measures the pulse\n * @param value the value of the pulse (default high)\n * @param maximum duration in micro-seconds\n */\n //% blockId=\"pins_pulse_in\" block=\"pulse in (µs)|pin %name|pulsed %high||timeout %maxDuration (µs)\"\n //% weight=18 blockGap=8\n //% help=\"pins/pulse-in\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 maxDuration.defl=2000000 shim=DigitalInOutPinMethods::pulseIn\n pulseIn(value: PulseValue, maxDuration?: int32): int32;\n\n /**\n * Set the pull direction of this pin.\n * @param name pin to set the pull mode on\n * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone\n */\n //% help=pins/set-pull weight=17 blockGap=8\n //% blockId=device_set_pull block=\"set pull|pin %pin|to %pull\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::setPull\n setPull(pull: PinPullMode): void;\n}\n\n\ndeclare interface PwmPin {}\n\n\ndeclare interface PwmOnlyPin {\n /**\n * Set the Pulse-width modulation (PWM) period of the analog output. The period is in\n * **microseconds** or `1/1000` milliseconds.\n * If this pin is not configured as an analog output (using `analog write pin`), the operation has\n * no effect.\n * @param name analog pin to set period to\n * @param micros period in micro seconds. eg:20000\n */\n //% help=pins/analog-set-period weight=51\n //% blockId=device_set_analog_period block=\"analog set period|pin %pin|to (µs)%period\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::analogSetPeriod\n analogSetPeriod(period: int32): void;\n\n /**\n * Write a value to the servo to control the rotation of the shaft. On a standard servo, this will\n * set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous\n * rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one\n * direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).\n * @param name pin to write to\n * @param value angle or rotation speed\n */\n //% help=pins/servo-write weight=41 group=\"Servo\"\n //% blockId=device_set_servo_pin block=\"servo write|pin %name|to %value=protractorPicker\" blockGap=8\n //% parts=microservo trackArgs=0\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.defl=90 shim=PwmOnlyPinMethods::servoWrite\n servoWrite(value?: int32): void;\n\n /**\n * Set the pin for PWM analog output, make the period be 20 ms, and set the pulse width.\n * The pulse width is based on the value it is given **microseconds** or `1/1000` milliseconds.\n * @param name pin name\n * @param duration pulse duration in micro seconds, eg:1500\n */\n //% help=pins/servo-set-pulse weight=40 group=\"Servo\" blockGap=8\n //% blockId=device_set_servo_pulse block=\"servo set pulse|pin %value|to (µs) %duration\"\n //% parts=microservo blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::servoSetPulse\n servoSetPulse(duration: int32): void;\n\n /**\n * Indicates if the servo is running continuously\n */\n //% blockHidden=1 shim=PwmOnlyPinMethods::servoSetContinuous\n servoSetContinuous(continuous: boolean): void;\n}\ndeclare namespace control {\n\n /**\n * Announce that an event happened to registered handlers.\n * @param src ID of the MicroBit Component that generated the event\n * @param value Component specific code indicating the cause of the event.\n */\n //% weight=21 blockGap=12 blockId=\"control_raise_event\"\n //% help=control/raise-event\n //% block=\"raise event|from %src|with value %value\" blockExternalInputs=1 shim=control::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Determine the version of system software currently running.\n */\n //% blockId=\"control_device_dal_version\" block=\"device dal version\"\n //% help=control/device-dal-version shim=control::deviceDalVersion\n function deviceDalVersion(): string;\n\n /**\n * Allocates the next user notification event\n */\n //% help=control/allocate-notify-event shim=control::allocateNotifyEvent\n function allocateNotifyEvent(): int32;\n\n /** Write a message to DMESG debugging buffer. */\n //% shim=control::dmesg\n function dmesg(s: string): void;\n\n /** Write a message and value (pointer) to DMESG debugging buffer. */\n //% shim=control::dmesgPtr\n function dmesgPtr(str: string, ptr: Object): void;\n}\n\n\ndeclare interface I2C {\n /**\n * Read `size` bytes from a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::readBuffer\n readBuffer(address: int32, size: int32, repeat?: boolean): Buffer;\n\n /**\n * Write bytes to a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::writeBuffer\n writeBuffer(address: int32, buf: Buffer, repeat?: boolean): int32;\n}\ndeclare namespace pins {\n\n /**\n * Opens a Serial communication driver\n */\n //% help=pins/create-i2c\n //% parts=i2c shim=pins::createI2C\n function createI2C(sda: DigitalInOutPin, scl: DigitalInOutPin): I2C;\n}\ndeclare namespace pins {\n\n /**\n * Opens a SPI driver\n */\n //% help=pins/create-spi\n //% parts=spi shim=pins::createSPI\n function createSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin): SPI;\n\n /**\n * Opens a slave SPI driver\n */\n //% parts=spi shim=pins::createSlaveSPI\n function createSlaveSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin, csPin: DigitalInOutPin): SPI;\n}\n\n\ndeclare interface SPI {\n /**\n * Write to the SPI bus\n */\n //% shim=SPIMethods::write\n write(value: int32): int32;\n\n /**\n * Transfer buffers over the SPI bus\n */\n //% argsNullable shim=SPIMethods::transfer\n transfer(command: Buffer, response: Buffer): void;\n\n /**\n * Sets the SPI clock frequency\n */\n //% shim=SPIMethods::setFrequency\n setFrequency(frequency: int32): void;\n\n /**\n * Sets the SPI bus mode\n */\n //% shim=SPIMethods::setMode\n setMode(mode: int32): void;\n}\ndeclare namespace configStorage {\n\n /**\n * Puts an entry in the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n * @param value the data (max 32 characters)\n */\n //% shim=configStorage::setBuffer\n function setBuffer(key: string, value: Buffer): void;\n\n /**\n * Gets an entry from the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::getBuffer\n function getBuffer(key: string): Buffer;\n\n /**\n * Removes the key from local storage\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::removeItem\n function removeItem(key: string): void;\n\n /**\n * Clears the local storage\n */\n //% shim=configStorage::clear\n function clear(): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1560,7 +1560,7 @@ var pxtTargetBundle = {
1560
1560
  "platform.cpp": "#include \"pxt.h\"\n\n#include \"RP2040LowLevelTimer.h\"\n\n#include \"hardware/pll.h\"\n#include \"hardware/clocks.h\"\n#include \"hardware/structs/rosc.h\"\n\nnamespace pxt {\n\nLowLevelTimer *allocateTimer() {\n // TODO: add config to low level timer\n return new RP2040LowLevelTimer();\n}\n\nstatic uint32_t hw_random(void) {\n uint8_t buf[16];\n for (unsigned i = 0; i < sizeof(buf); ++i) {\n buf[i] = 0;\n for (int j = 0; j < 8; ++j) {\n buf[i] <<= 1;\n if (rosc_hw->randombit)\n buf[i] |= 1;\n }\n }\n return hash_fnv1(buf, sizeof(buf));\n}\n\nstatic void initRandomSeed() {\n seedRandom(hw_random());\n}\n\nvoid deepSleep() {}\n\nvoid platform_init() {\n initRandomSeed();\n}\n\nint *getBootloaderConfigData() {\n static bool inited;\n static int *cached;\n\n if (!inited) {\n inited = 1;\n for (int i = 1; i <= 64; i *= 2) {\n uint32_t *p = (uint32_t *)(XIP_BASE + i * 1024 * 1024 - 4096);\n if (p[0] == CFG_MAGIC0 && p[1] == CFG_MAGIC1) {\n cached = (int *)p;\n break;\n }\n }\n }\n\n return cached;\n}\n\n} // namespace pxt\n\nvoid cpu_clock_init() {\n // missing in Codal\n}\n",
1561
1561
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n#include \"Image.h\"\n#include \"Timer.h\"\n\n#include \"RP2040.h\"\n#include \"RP2040Pin.h\"\n#include \"RP2040Spi.h\"\n#include \"RP2040I2C.h\"\n#include \"RP2040PWM.h\"\n\n#define IMAGE_BITS 4\n\n#define PAGE_SIZE 256\n#define DEV_NUM_PINS 30\n\n// all pins with pwm output\n#define DEV_PWM_PINS 0x3FFFFFFF\n// 26~29 has adc input\n#define DEV_AIN_PINS 0x3C000000\n\n// Codal doesn't yet distinguish between PWM and AIN\n#define DEV_ANALOG_PINS (DEV_PWM_PINS | DEV_AIN_PINS)\n\n#define CODAL_PIN RP2040Pin\n#define CODAL_SPI RP2040SPI\n#define CODAL_I2C RP2040I2C\n#define CODAL_TIMER Timer\n\n#define UF2_INFO_TXT \"UF2 Bootloader v1.0\\nModel: Raspberry Pi RP2\\nBoard-ID: RPI-RP2\"\n\ntypedef uint8_t PinName;\n\n// XIP range in 0x1000_0000 ~ 0x1100_0000\n#define PXT_IS_READONLY(v) (isTagged(v) || ((uintptr_t)v & 0x10000000))\n\n#define P0 0\n#define P1 1\n#define P2 2\n#define P3 3\n#define P4 4\n#define P5 5\n#define P6 6\n#define P7 7\n#define P8 8\n#define P9 9\n#define P10 10\n#define P11 11\n#define P12 12\n#define P13 13\n#define P14 14\n#define P15 15\n#define P16 16\n#define P17 17\n#define P18 18\n#define P19 19\n#define P20 20\n#define P21 21\n#define P22 22\n#define P23 23\n#define P24 24\n#define P25 25\n#define P26 26\n#define P27 27\n#define P28 28\n#define P29 29\n#define P30 30\n\n#endif",
1562
1562
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#include \"CodalConfig.h\"\n#include \"CodalHeapAllocator.h\"\n#include \"CodalDevice.h\"\n#include \"CodalDmesg.h\"\n#include \"ErrorNo.h\"\n#include \"Timer.h\"\n#include \"Matrix4.h\"\n#include \"CodalCompat.h\"\n#include \"CodalComponent.h\"\n#include \"ManagedType.h\"\n#include \"Event.h\"\n#include \"NotifyEvents.h\"\n#include \"Button.h\"\n#include \"CodalFiber.h\"\n#include \"MessageBus.h\"\n#include \"MultiButton.h\"\n\nusing namespace codal;\n\n// codal::ManagedString compat\n#define MSTR(s) codal::ManagedString((s)->data, (s)->length)\n#define PSTR(s) mkString((s).toCharArray(), (s).length())\n\n#include \"pins.h\"\n\n#if CONFIG_ENABLED(DEVICE_USB)\n#include \"hf2.h\"\n#include \"hf2dbg.h\"\n#if CONFIG_ENABLED(DEVICE_MOUSE)\n#include \"HIDMouse.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\n#include \"HIDKeyboard.h\"\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\n#include \"HIDJoystick.h\"\n#endif\n#endif\n\n#define PXT_COMM_BASE 0x20002000 // 8k in\n\n// old codal compat\n#ifndef REAL_TIME_FUNC\n#define REAL_TIME_FUNC /* */\n#endif\n\nnamespace pxt {\n\n#if CONFIG_ENABLED(DEVICE_USB)\nextern CodalUSB usb;\nextern HF2 hf2;\n#if CONFIG_ENABLED(DEVICE_MOUSE)\nextern USBHIDMouse mouse;\n#endif\n#if CONFIG_ENABLED(DEVICE_KEYBOARD)\nextern USBHIDKeyboard keyboard;\n#endif\n#if CONFIG_ENABLED(DEVICE_JOYSTICK)\nextern USBHIDJoystick joystick;\n#endif\n#endif\n\n// Utility functions\nextern Event lastEvent;\nextern CODAL_TIMER devTimer;\nextern MessageBus devMessageBus;\nextern codal::CodalDevice device;\n\nvoid set_usb_strings(const char *uf2_info);\nextern void (*logJDFrame)(const uint8_t *data);\nextern void (*sendJDFrame)(const uint8_t *data);\n\nstatic inline void raiseEvent(int src, int val) {\n Event(src, val);\n}\n\n} // namespace pxt\n\nnamespace pins {\nclass CodalSPIProxy;\nclass CodalI2CProxy;\n} // namespace pins\n\ntypedef pins::CodalI2CProxy* I2C_;\ntypedef pins::CodalSPIProxy* SPI_;\n\nnamespace pxt {\ncodal::LowLevelTimer *allocateTimer();\n\n#ifdef CODAL_I2C\nCODAL_I2C* getI2C(DigitalInOutPin sda, DigitalInOutPin scl);\n#endif\nCODAL_SPI* getSPI(DigitalInOutPin mosi, DigitalInOutPin miso, DigitalInOutPin sck);\n#ifdef CODAL_JACDAC_WIRE_SERIAL\nLowLevelTimer* getJACDACTimer();\n#endif\nclass PressureButton;\nuint32_t readButtonMultiplexer(int bits);\nvoid disableButtonMultiplexer();\n}\n\nnamespace serial {\nclass CodalSerialDeviceProxy;\n}\n\ntypedef serial::CodalSerialDeviceProxy* SerialDevice;\n\nnamespace jacdac {\nclass JDProxyDriver;\n} // namespace network\n\ntypedef jacdac::JDProxyDriver* JacDacDriverStatus;\n\n#define DEVICE_ID_BUTTON_SLIDE 3000\n#define DEVICE_ID_MICROPHONE 3001\n#define DEVICE_ID_FIRST_BUTTON 4000\n#define DEVICE_ID_FIRST_TOUCHBUTTON 4100\n\n#define PXT_INTERNAL_KEY_UP 2050\n#define PXT_INTERNAL_KEY_DOWN 2051\n\n#endif\n",
1563
- "pxt.json": "{\n \"name\": \"core---rp2040\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1563
+ "pxt.json": "{\n \"name\": \"core---rp2040\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"dal.d.ts\",\n \"codal.cpp\",\n \"usb.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"pins.cpp\",\n \"pinsAnalog.cpp\",\n \"pinsDigital.cpp\",\n \"pinsPWM.cpp\",\n \"pins.ts\",\n \"pinscompat.ts\",\n \"control.cpp\",\n \"i2c.cpp\",\n \"i2c.ts\",\n \"spi.cpp\",\n \"spi.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"hf2.cpp\",\n \"hf2.h\",\n \"hf2dbg.h\",\n \"uf2format.h\",\n \"uf2hid.h\",\n \"ns.ts\",\n \"dmac.cpp\",\n \"dmac.h\",\n \"timer.ts\",\n \"light.cpp\",\n \"light.h\",\n \"keyvaluestorage.cpp\",\n \"keyvaluestorage.ts\",\n \"leveldetector.ts\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1564
1564
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include \"CodalDmesg.h\"\n#include \"CodalHeapAllocator.h\"\n\n#define PXT_CODAL 1\n\n#define itoa(a, b) codal::itoa(a, b)\n\n#define GC_GET_HEAP_SIZE() device_heap_size(0)\n#define GC_STACK_BASE DEVICE_STACK_BASE\n#define xmalloc device_malloc\n#define xfree device_free\n\n// on most devices we allocate the entire heap at once, so large allocs should work\n// if they don't you just get the regular out of memory instead of alloc too large\n#define GC_MAX_ALLOC_SIZE (128 * 1024)\n\n#endif\n",
1565
1565
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1566
1566
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace light {\n\n /**\n * Send a programmable light buffer to the specified digital pin\n * @param data The pin that the lights are connected to\n * @param clk the clock line if any\n * @param mode the color encoding mode\n * @param buf The buffer to send to the pin\n */\n //% shim=light::sendBuffer\n function sendBuffer(data: DigitalInOutPin, clk: DigitalInOutPin, mode: int32, buf: Buffer): void;\n}\ndeclare namespace control {\n\n /**\n * Determines if the USB has been enumerated.\n */\n //% shim=control::isUSBInitialized\n function isUSBInitialized(): boolean;\n}\ndeclare namespace pins {\n\n /**\n * Get a pin by configuration id (DAL.CFG_PIN...)\n */\n //% shim=pins::pinByCfg\n function pinByCfg(key: int32): DigitalInOutPin;\n\n /**\n * Create a new zero-initialized buffer.\n * @param size number of bytes in the buffer\n */\n //% shim=pins::createBuffer\n function createBuffer(size: int32): Buffer;\n\n /**\n * Get the duration of the last pulse in microseconds. This function should be called from a\n * ``onPulsed`` handler.\n */\n //% help=pins/pulse-duration blockGap=8\n //% blockId=pins_pulse_duration block=\"pulse duration (µs)\"\n //% weight=19 shim=pins::pulseDuration\n function pulseDuration(): int32;\n}\n\n\ndeclare interface AnalogInPin {\n /**\n * Read the connector value as analog, that is, as a value comprised between 0 and 1023.\n * @param name pin to write to\n */\n //% help=pins/analog-read weight=53\n //% blockId=device_get_analog_pin block=\"analog read|pin %name\" blockGap=\"8\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=AnalogInPinMethods::analogRead\n analogRead(): int32;\n}\n\n\ndeclare interface AnalogOutPin {\n /**\n * Set the connector value as analog. Value must be comprised between 0 and 1023.\n * @param name pin name to write to\n * @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0\n */\n //% help=pins/analog-write weight=52\n //% blockId=device_set_analog_pin block=\"analog write|pin %name|to %value\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.min=0 value.max=1023 shim=AnalogOutPinMethods::analogWrite\n analogWrite(value: int32): void;\n}\n\n\ndeclare interface DigitalInOutPin {\n /**\n * Read a pin or connector as either 0 or 1\n * @param name pin to read from\n */\n //% help=pins/digital-read weight=61\n //% blockId=device_get_digital_pin block=\"digital read|pin %name\" blockGap=8\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalRead\n digitalRead(): boolean;\n\n /**\n * Set a pin or connector value to either 0 or 1.\n * @param name pin to write to\n * @param value value to set on the pin\n */\n //% help=pins/digital-write weight=60\n //% blockId=device_set_digital_pin block=\"digital write|pin %name|to %value=toggleHighLow\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::digitalWrite\n digitalWrite(value: boolean): void;\n\n /**\n * Make this pin a digital input, and create events where the timestamp is the duration\n * that this pin was either ``high`` or ``low``.\n */\n //% help=pins/on-pulsed weight=16 blockGap=8\n //% blockId=pins_on_pulsed block=\"on|pin %pin|pulsed %pulse\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4\n //% deprecated=1 hidden=1 shim=DigitalInOutPinMethods::onPulsed\n onPulsed(pulse: PulseValue, body: () => void): void;\n\n /**\n * Register code to run when a pin event occurs. \n */\n //% help=pins/on-event weight=20 blockGap=8\n //% blockId=pinsonevent block=\"on|pin %pin|%event\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 shim=DigitalInOutPinMethods::onEvent\n onEvent(event: PinEvent, body: () => void): void;\n\n /**\n * Return the duration of a pulse in microseconds\n * @param name the pin which measures the pulse\n * @param value the value of the pulse (default high)\n * @param maximum duration in micro-seconds\n */\n //% blockId=\"pins_pulse_in\" block=\"pulse in (µs)|pin %name|pulsed %high||timeout %maxDuration (µs)\"\n //% weight=18 blockGap=8\n //% help=\"pins/pulse-in\"\n //% blockNamespace=pins\n //% pin.fieldEditor=\"gridpicker\"\n //% pin.fieldOptions.width=220\n //% pin.fieldOptions.columns=4 maxDuration.defl=2000000 shim=DigitalInOutPinMethods::pulseIn\n pulseIn(value: PulseValue, maxDuration?: int32): int32;\n\n /**\n * Set the pull direction of this pin.\n * @param name pin to set the pull mode on\n * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone\n */\n //% help=pins/set-pull weight=17 blockGap=8\n //% blockId=device_set_pull block=\"set pull|pin %pin|to %pull\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=DigitalInOutPinMethods::setPull\n setPull(pull: PinPullMode): void;\n}\n\n\ndeclare interface PwmPin {}\n\n\ndeclare interface PwmOnlyPin {\n /**\n * Set the Pulse-width modulation (PWM) period of the analog output. The period is in\n * **microseconds** or `1/1000` milliseconds.\n * If this pin is not configured as an analog output (using `analog write pin`), the operation has\n * no effect.\n * @param name analog pin to set period to\n * @param micros period in micro seconds. eg:20000\n */\n //% help=pins/analog-set-period weight=51\n //% blockId=device_set_analog_period block=\"analog set period|pin %pin|to (µs)%period\"\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::analogSetPeriod\n analogSetPeriod(period: int32): void;\n\n /**\n * Write a value to the servo to control the rotation of the shaft. On a standard servo, this will\n * set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous\n * rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one\n * direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).\n * @param name pin to write to\n * @param value angle or rotation speed\n */\n //% help=pins/servo-write weight=41 group=\"Servo\"\n //% blockId=device_set_servo_pin block=\"servo write|pin %name|to %value=protractorPicker\" blockGap=8\n //% parts=microservo trackArgs=0\n //% blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4\n //% value.defl=90 shim=PwmOnlyPinMethods::servoWrite\n servoWrite(value?: int32): void;\n\n /**\n * Set the pin for PWM analog output, make the period be 20 ms, and set the pulse width.\n * The pulse width is based on the value it is given **microseconds** or `1/1000` milliseconds.\n * @param name pin name\n * @param duration pulse duration in micro seconds, eg:1500\n */\n //% help=pins/servo-set-pulse weight=40 group=\"Servo\" blockGap=8\n //% blockId=device_set_servo_pulse block=\"servo set pulse|pin %value|to (µs) %duration\"\n //% parts=microservo blockNamespace=pins\n //% name.fieldEditor=\"gridpicker\"\n //% name.fieldOptions.width=220\n //% name.fieldOptions.columns=4 shim=PwmOnlyPinMethods::servoSetPulse\n servoSetPulse(duration: int32): void;\n\n /**\n * Indicates if the servo is running continuously\n */\n //% blockHidden=1 shim=PwmOnlyPinMethods::servoSetContinuous\n servoSetContinuous(continuous: boolean): void;\n}\ndeclare namespace control {\n\n /**\n * Announce that an event happened to registered handlers.\n * @param src ID of the MicroBit Component that generated the event\n * @param value Component specific code indicating the cause of the event.\n */\n //% weight=21 blockGap=12 blockId=\"control_raise_event\"\n //% help=control/raise-event\n //% block=\"raise event|from %src|with value %value\" blockExternalInputs=1 shim=control::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Determine the version of system software currently running.\n */\n //% blockId=\"control_device_dal_version\" block=\"device dal version\"\n //% help=control/device-dal-version shim=control::deviceDalVersion\n function deviceDalVersion(): string;\n\n /**\n * Allocates the next user notification event\n */\n //% help=control/allocate-notify-event shim=control::allocateNotifyEvent\n function allocateNotifyEvent(): int32;\n\n /** Write a message to DMESG debugging buffer. */\n //% shim=control::dmesg\n function dmesg(s: string): void;\n\n /** Write a message and value (pointer) to DMESG debugging buffer. */\n //% shim=control::dmesgPtr\n function dmesgPtr(str: string, ptr: Object): void;\n}\n\n\ndeclare interface I2C {\n /**\n * Read `size` bytes from a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::readBuffer\n readBuffer(address: int32, size: int32, repeat?: boolean): Buffer;\n\n /**\n * Write bytes to a 7-bit I2C `address`.\n */\n //% repeat.defl=0 shim=I2CMethods::writeBuffer\n writeBuffer(address: int32, buf: Buffer, repeat?: boolean): int32;\n}\ndeclare namespace pins {\n\n /**\n * Opens a Serial communication driver\n */\n //% help=pins/create-i2c\n //% parts=i2c shim=pins::createI2C\n function createI2C(sda: DigitalInOutPin, scl: DigitalInOutPin): I2C;\n}\ndeclare namespace pins {\n\n /**\n * Opens a SPI driver\n */\n //% help=pins/create-spi\n //% parts=spi shim=pins::createSPI\n function createSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin): SPI;\n\n /**\n * Opens a slave SPI driver\n */\n //% parts=spi shim=pins::createSlaveSPI\n function createSlaveSPI(mosiPin: DigitalInOutPin, misoPin: DigitalInOutPin, sckPin: DigitalInOutPin, csPin: DigitalInOutPin): SPI;\n}\n\n\ndeclare interface SPI {\n /**\n * Write to the SPI bus\n */\n //% shim=SPIMethods::write\n write(value: int32): int32;\n\n /**\n * Transfer buffers over the SPI bus\n */\n //% argsNullable shim=SPIMethods::transfer\n transfer(command: Buffer, response: Buffer): void;\n\n /**\n * Sets the SPI clock frequency\n */\n //% shim=SPIMethods::setFrequency\n setFrequency(frequency: int32): void;\n\n /**\n * Sets the SPI bus mode\n */\n //% shim=SPIMethods::setMode\n setMode(mode: int32): void;\n}\ndeclare namespace configStorage {\n\n /**\n * Puts an entry in the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n * @param value the data (max 32 characters)\n */\n //% shim=configStorage::setBuffer\n function setBuffer(key: string, value: Buffer): void;\n\n /**\n * Gets an entry from the device storage. Key may have up to 16 characters (bytes).\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::getBuffer\n function getBuffer(key: string): Buffer;\n\n /**\n * Removes the key from local storage\n * @param key the identifier (max 16 characters)\n */\n //% shim=configStorage::removeItem\n function removeItem(key: string): void;\n\n /**\n * Clears the local storage\n */\n //% shim=configStorage::clear\n function clear(): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
@@ -1588,7 +1588,7 @@ var pxtTargetBundle = {
1588
1588
  "platform.h": "#ifndef __PXT_PLATFORM_H\n#define __PXT_PLATFORM_H\n\n#define PAGE_SIZE 1024 // not really\n\n#define DEV_NUM_PINS 28\n\n#define DEV_PWM_PINS 0xffffffffULL\n#define DEV_AIN_PINS 0ULL\n\n// Codal doesn't yet distinguish between PWM and AIN\n#define DEV_ANALOG_PINS (DEV_PWM_PINS | DEV_AIN_PINS)\n\n#define CODAL_PIN ZPin\n#define CODAL_TIMER ZTimer\n#define CODAL_SPI ZSPI\n#define CODAL_I2C ZI2C\n\nconst char *vm_settings_dir(void);\n#define SETTINGSDIR vm_settings_dir()\n\nnamespace pxt {\n\nclass ZPin;\nclass AbstractButton;\nclass MultiButton;\nclass CodalComponent;\n\ntypedef void (*reset_fn_t)();\nvoid registerResetFunction(reset_fn_t fn);\nvoid soft_panic(int errorCode);\n} // namespace pxt\n\n#define IMAGE_BITS 4\n\n#define PXT_IN_ISR() false\n\n#define GC_BLOCK_SIZE (1024 * 64)\n\n#define PXT_REGISTER_RESET(fn) pxt::registerResetFunction(fn)\n\n#ifdef __APPLE__\n#include \"TargetConditionals.h\"\n#if TARGET_OS_IPHONE\n#define PXT_IOS 1\n#endif\n#endif\n\n#if defined(PXT64) || defined(__MINGW32__)\n#define GC_BASE 0x2000000000\n#define GC_PAGE_SIZE (64 * 1024)\n\n// always allocate 1M of heap\n#define PXT_VM_HEAP_ALLOC_BITS 20\nextern uint8_t *gcBase;\n#define PXT_IS_READONLY(v) \\\n (!isPointer(v) || (((uintptr_t)v - (uintptr_t)gcBase) >> PXT_VM_HEAP_ALLOC_BITS) != 0)\n\n#else // PXT32\n#define GC_BASE 0x20000000\n#define GC_PAGE_SIZE 4096\n\n#endif // PXT32 vs 64\n\n#endif\n",
1589
1589
  "platform_includes.h": "#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#include <sys/types.h>\n\n#define PROCESSOR_WORD_TYPE uintptr_t\n",
1590
1590
  "pxt.h": "#ifndef __PXT_H\n#define __PXT_H\n\n#include \"pxtbase.h\"\n\n#include \"vm.h\"\n\n#define OUTPUT_BITS 12\n\n#define DEVICE_EVT_ANY 0\n#define DEVICE_ID_NOTIFY_ONE 1022\n#define DEVICE_ID_NOTIFY 1023\n\nnamespace pxt {\nvoid raiseEvent(int id, int event);\nint allocateNotifyEvent();\nvoid sleep_core_us(uint64_t us);\n\nvoid target_disable_irq();\nvoid target_enable_irq();\n\nclass Button;\ntypedef Button *Button_;\n\nextern \"C\" void target_init();\n\nextern volatile bool paniced;\nextern char **initialArgv;\nvoid target_exit();\nextern volatile int panicCode;\n\n// Buffer, Sound, and Image share representation.\ntypedef Buffer Sound;\n\n} // namespace pxt\n\n#undef PXT_MAIN\n#define PXT_MAIN \\\n int main(int argc, char **argv) { \\\n pxt::initialArgv = argv; \\\n pxt::vmStart(); \\\n return 0; \\\n }\n\n#undef PXT_SHIMS_BEGIN\n#define PXT_SHIMS_BEGIN \\\n namespace pxt { \\\n const OpcodeDesc staticOpcodes[] __attribute__((aligned(0x20))) = {\n\n#undef PXT_SHIMS_END\n#define PXT_SHIMS_END \\\n { 0, 0, 0 } \\\n } \\\n ; \\\n }\n\n#endif\n",
1591
- "pxt.json": "{\n \"name\": \"core---vm\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"Makefile\",\n \"dal.d.ts\",\n \"scheduler.cpp\",\n \"config.cpp\",\n \"target.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"control.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\",\n \"timer.ts\",\n \"platform_includes.h\",\n \"codalemu.cpp\",\n \"dmesg.cpp\",\n \"keys.cpp\",\n \"vm.cpp\",\n \"vmload.cpp\",\n \"vm.h\",\n \"vmcache.cpp\",\n \"verify.cpp\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1591
+ "pxt.json": "{\n \"name\": \"core---vm\",\n \"description\": \"The core library for Codal-based targets\",\n \"dependencies\": {\n \"base\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"Makefile\",\n \"dal.d.ts\",\n \"scheduler.cpp\",\n \"config.cpp\",\n \"target.cpp\",\n \"pxt.h\",\n \"platform.h\",\n \"platform.cpp\",\n \"pxtcore.h\",\n \"pins.h\",\n \"control.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\",\n \"timer.ts\",\n \"platform_includes.h\",\n \"codalemu.cpp\",\n \"dmesg.cpp\",\n \"keys.cpp\",\n \"vm.cpp\",\n \"vmload.cpp\",\n \"vm.h\",\n \"vmcache.cpp\",\n \"verify.cpp\",\n \"pxtparts.json\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"yotta\": {\n \"config\": {\n \"codal\": {\n \"component_count\": 64,\n \"dmesg_buffer_size\": 1024\n }\n }\n },\n \"dalDTS\": {\n \"includeDirs\": [\n \"libraries/codal-core/inc\",\n \"pxtapp\"\n ],\n \"excludePrefix\": [\n \"JD_\",\n \"USB_\",\n \"REQUEST_\",\n \"LIS3DH_\",\n \"FXOS8700_\",\n \"HF2_\",\n \"PXT_REF_TAG_\",\n \"MS_\",\n \"SCSI_\",\n \"MAG_\",\n \"MAG3\",\n \"MPU6\",\n \"MADCTL\",\n \"MMA8\"\n ]\n }\n}\n",
1592
1592
  "pxtcore.h": "#ifndef __PXTCORE_H\n#define __PXTCORE_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n\nnamespace pxt {\nvoid *gcAllocBlock(size_t sz);\nvoid vm_stack_trace();\n}\n\nextern \"C\" void dmesg(const char *fmt, ...);\nextern \"C\" void vdmesg(const char *format, va_list arg);\n#define DMESG ::dmesg\n\nstatic inline void itoa(int v, char *dst) {\n snprintf(dst, 30, \"%d\", v);\n}\n\nextern \"C\" void *xmalloc(size_t sz);\n#define xfree free\n\n#define GC_ALLOC_BLOCK gcAllocBlock\n\n#ifndef POKY\n// This seems to degrade performance - probably due to cache size\n//#define GC_BLOCK_SIZE (1024 * 64)\n#endif\n\n#define PXT_HARD_FLOAT 1\n\n#endif\n",
1593
1593
  "pxtparts.json": "{\n \"neopixel\": {\n \"simulationBehavior\": \"neopixel\",\n \"visual\": {\n \"builtIn\": \"neopixel\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 19,\n \"y\": 0\n },\n {\n \"x\": 28,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createStrip,light.createNeoPixelStrip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"dotstar\": {\n \"simulationBehavior\": \"dotstar\",\n \"visual\": {\n \"builtIn\": \"dotstar\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 1\n },\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"light.createAPA102Strip\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"dataPin\"\n },\n {\n \"pinInstantiationIdx\": 1,\n \"partParameter\": \"clkPin\"\n },\n {\n \"partParameter\": \"mode\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n },\n \"pixels\": {\n \"simulationBehavior\": \"pixels\",\n \"visual\": { \n \"builtIn\": \"pixels\",\n \"width\": 58,\n \"height\": 113,\n \"pinDistance\": 9,\n \"pinLocations\": [\n {\n \"x\": 10,\n \"y\": 0\n },\n {\n \"x\": 17,\n \"y\": 0\n },\n {\n \"x\": 24,\n \"y\": 0\n },\n {\n \"x\": 31,\n \"y\": 0\n }\n ]\n },\n \"numberOfPins\": 4,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"MOSI\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"SCK\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"solder\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1, 2\n ]\n },\n {\n \"pinIndices\": [\n 3\n ]\n }\n ]\n }, \n \"buttons\": {\n \"simulationBehavior\": \"buttons\",\n \"visual\": {\n \"builtIn\": \"buttons\",\n \"width\": 75,\n \"height\": 45,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 30,\n \"y\": 45\n }\n ]\n },\n \"numberOfPins\": 2,\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"Button.onEvent,Button.isPressed,Button.wasPressed\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"button\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"slideswitch\": {\n \"numberOfPins\": 3,\n \"simulationBehavior\": \"slideswitch\",\n \"visual\": {\n \"builtIn\": \"slideswitch\",\n \"width\": 100,\n \"height\": 100,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 0\n },\n {\n \"x\": 45,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalRead,DigitalInOutPin.onPulsed,DigitalInOutPin.onEvent\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"pin\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"microservo\": {\n \"simulationBehavior\": \"microservo\",\n \"visual\": {\n \"builtIn\": \"microservo\",\n \"width\": 74.85,\n \"height\": 200,\n \"pinDistance\": 10,\n \"pinLocations\": [\n {\n \"x\": 30,\n \"y\": 5\n },\n {\n \"x\": 37,\n \"y\": 5\n },\n {\n \"x\": 45,\n \"y\": 5\n }\n ]\n },\n \"numberOfPins\": 3,\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"+Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"PwmOnlyPin.servoWrite,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 2\n ]\n },\n {\n \"pinIndices\": [\n 0,\n 1\n ]\n }\n ]\n },\n \"led\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"DigitalInOutPin.digitalWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"analogled\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"builtIn\": \"led\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"led\",\n \"pinDefinitions\": [\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogOutPin.analogWrite\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n },\n \"photocell\": {\n \"numberOfPins\": 3,\n \"visual\": {\n \"builtIn\": \"photocell\",\n \"width\": 68,\n \"height\": 180,\n \"pinDistance\": 15,\n \"pinLocations\": [\n {\n \"x\": 0,\n \"y\": 0\n },\n {\n \"x\": 15,\n \"y\": 0\n },\n {\n \"x\": 60,\n \"y\": 0\n }\n ]\n },\n \"simulationBehavior\": \"photocell\",\n \"pinDefinitions\": [\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": {\n \"pinInstantiationIdx\": 0\n },\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"function\",\n \"fullyQualifiedName\": \"AnalogInPin.analogRead\",\n \"argumentRoles\": [\n {\n \"pinInstantiationIdx\": 0,\n \"partParameter\": \"name\"\n }\n ]\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1594
1594
  "scheduler.cpp": "#include \"pxt.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <sys/time.h>\n#include <time.h>\n#include <unistd.h>\n#include <signal.h>\n#include <sys/types.h>\n#include <errno.h>\n\n#ifndef PXT_ESP32\n// __MINGW32__ is defined on both mingw32 and mingw64\n#ifdef __MINGW32__\n#include <windows.h>\n#else\n#include <sys/mman.h>\n#endif\n#endif\n\n#define HANDLER_RUNNING 0x0001\n\n// should this be something like CXX11 or whatever?\n#define THROW throw()\n#define THREAD_DBG(...)\n\nstatic uint8_t in_xmalloc_panic;\n\nvoid *xmalloc(size_t sz) {\n auto r = malloc(sz);\n if (r == NULL) {\n DMESG(\"failed to allocate %d bytes\", sz);\n if (in_xmalloc_panic) {\n target_panic(PANIC_GC_OOM);\n } else {\n in_xmalloc_panic = 1;\n soft_panic(PANIC_GC_OOM); // this can happen on esp32 etc; shouldn't on linux/ios etc\n }\n }\n return r;\n}\n\nvoid *operator new(size_t size) {\n return xmalloc(size);\n}\nvoid *operator new[](size_t size) {\n return xmalloc(size);\n}\n\nvoid operator delete(void *p)THROW {\n xfree(p);\n}\nvoid operator delete[](void *p) THROW {\n xfree(p);\n}\n\nuint8_t *gcBase;\n\nnamespace pxt {\n\n#ifndef PXT_ESP32\nstatic uint64_t startTime;\n#endif\n\nFiberContext *allFibers;\nFiberContext *currentFiber;\nstatic pthread_mutex_t eventMutex;\nstatic pthread_cond_t newEventBroadcast;\n\nstatic struct Event *eventHead, *eventTail;\n\nstruct Event {\n struct Event *next;\n int source;\n int value;\n};\n\nEvent lastEvent;\n\nEvent *mkEvent(int source, int value) {\n auto res = new Event();\n memset(res, 0, sizeof(Event));\n res->source = source;\n res->value = value;\n return res;\n}\n\nvolatile int panicCode;\nextern \"C\" void drawPanic(int code);\n\nvoid schedule() {\n auto f = currentFiber;\n if (!f->wakeTime && !f->waitSource)\n oops(55);\n f->resumePC = f->pc;\n f->pc = NULL; // this will break the exec_loop()\n}\n\nvoid dmesg_flush();\n\nstatic void panic_core(int error_code) {\n int prevErr = errno;\n\n panicCode = error_code;\n\n drawPanic(error_code);\n\n DMESG(\"PANIC %d\", error_code % 1000);\n DMESG(\"errno=%d %s\", prevErr, strerror(prevErr));\n\n dmesg_flush();\n}\n\nextern \"C\" void target_panic(int error_code) {\n panic_core(error_code);\n\n#if defined(PXT_ESP32)\n // sleep_core_us(5 * 1000 * 1000);\n abort();\n#elif defined(PXT_VM)\n systemReset();\n#else\n while (1)\n sleep_core_us(10000);\n#endif\n}\n\nDLLEXPORT int pxt_get_panic_code() {\n return panicCode;\n}\n\nvoid ets_log_dmesg();\nvoid soft_panic(int errorCode) {\n if (errorCode >= 999)\n errorCode = 999;\n if (errorCode <= 0)\n errorCode = 1;\n vm_stack_trace();\n panic_core(1000 + errorCode);\n#if defined(PXT_ESP32)\n ets_log_dmesg();\n sleep_core_us(4000000);\n abort();\n#else\n systemReset();\n#endif\n}\n\nvoid sleep_core_us(uint64_t us) {\n#ifdef PXT_ESP32\n uint64_t endp = esp_timer_get_time() + us;\n while (esp_timer_get_time() < endp)\n ;\n#else\n struct timespec ts;\n ts.tv_sec = us / 1000000;\n ts.tv_nsec = (us % 1000000) * 1000;\n while (nanosleep(&ts, &ts))\n ;\n#endif\n}\n\nvoid target_yield() {\n#ifdef PXT_ESP32\n vTaskDelay(1);\n#else\n sleep_core_us(1000);\n#endif\n}\n\nvoid sleep_ms(uint32_t ms) {\n currentFiber->wakeTime = current_time_ms() + ms;\n schedule();\n}\n\nvoid sleep_us(uint64_t us) {\n if (us > 20000) {\n sleep_ms((uint32_t)(us / 1000));\n } else {\n sleep_core_us(us);\n }\n}\n\n#ifndef PXT_ESP32\nstatic uint64_t currTime() {\n struct timeval tv;\n gettimeofday(&tv, NULL);\n return tv.tv_sec * 1000000LL + tv.tv_usec;\n}\n\nuint64_t current_time_us() {\n if (!startTime)\n startTime = currTime();\n return currTime() - startTime;\n}\n#endif\n\nint current_time_ms() {\n return (int)(current_time_us() / 1000);\n}\n\nvoid disposeFiber(FiberContext *t) {\n if (allFibers == t) {\n allFibers = t->next;\n } else {\n for (auto tt = allFibers; tt; tt = tt->next) {\n if (tt->next == t) {\n tt->next = t->next;\n break;\n }\n }\n }\n\n // DMESG(\"free: %p %p\", t, t->stackCopy);\n\n xfree(t->stackCopy);\n xfree(t);\n\n if (currentFiber == t)\n currentFiber = NULL;\n}\n\n#define INITIAL_STACK_COPY_SIZE 16\n\nFiberContext *setupThread(Action a, TValue arg = 0, HandlerBinding *hb = NULL) {\n#if 0\n int numThreads = 0;\n for (auto p = allFibers; p; p = p->next)\n numThreads++;\n DMESG(\"setup thread: %p #%d\", a, numThreads);\n //if (numThreads > 10)\n // abort();\n#endif\n auto t = (FiberContext *)xmalloc(sizeof(FiberContext));\n memset(t, 0, sizeof(*t));\n if (!vmImg->stackBase) {\n vmImg->stackBase = (TValue *)xmalloc(VM_STACK_SIZE * sizeof(TValue));\n vmImg->stackTop = vmImg->stackBase + VM_STACK_SIZE;\n vmImg->stackLimit = vmImg->stackBase + VM_MAX_FUNCTION_STACK + 5;\n }\n t->stackCopy = (TValue *)xmalloc(sizeof(TValue) * INITIAL_STACK_COPY_SIZE);\n t->stackCopySize = INITIAL_STACK_COPY_SIZE;\n t->sp = vmImg->stackTop - 8;\n\n // DMESG(\"thr: %p %p\", t, t->stackCopy);\n\n auto ptr = t->stackCopy;\n *ptr++ = TAG_STACK_BOTTOM;\n *ptr++ = 0;\n *ptr++ = arg;\n *ptr++ = 0;\n *ptr++ = 0;\n *ptr++ = 0;\n *ptr++ = 0;\n *ptr++ = (TValue)0xf00df00df00df00d;\n\n t->handlerBinding = hb;\n auto ra = (RefAction *)a;\n // we only pass 1 argument, but can in fact handle up to 4\n if (ra->numArgs > 2)\n target_panic(PANIC_INVALID_IMAGE);\n t->currAction = ra;\n t->resumePC = actionPC(ra);\n\n t->img = vmImg;\n t->imgbase = (uint16_t *)vmImg->dataStart;\n\n // add at the end\n if (allFibers)\n for (auto p = allFibers; p; p = p->next) {\n if (!p->next) {\n p->next = t;\n break;\n }\n }\n else\n allFibers = t;\n\n return t;\n}\n\nvoid runInParallel(Action a) {\n setupThread(a);\n}\n\nvoid runForever(Action a) {\n auto f = setupThread(a);\n f->foreverPC = f->resumePC;\n}\n\nvoid waitForEvent(int source, int value) {\n currentFiber->waitSource = source;\n currentFiber->waitValue = value;\n schedule();\n}\n\nFiberContext *suspendFiber() {\n currentFiber->waitSource = PXT_WAIT_SOURCE_PROMISE;\n schedule();\n return currentFiber;\n}\n\nvoid resumeFiberWithFn(FiberContext *ctx, fiber_resume_t fn, void *arg) {\n if (ctx->waitSource != PXT_WAIT_SOURCE_PROMISE)\n oops(52);\n ctx->waitSource = 0;\n ctx->wakeFn = fn;\n ctx->wakeFnArg = arg;\n}\n\nvoid resumeFiber(FiberContext *ctx, TValue v) {\n if (ctx->waitSource != PXT_WAIT_SOURCE_PROMISE)\n oops(52);\n ctx->waitSource = 0;\n ctx->r0 = v;\n}\n\nstatic void startHandler(HandlerBinding *hb, Event &e) {\n if (!hb)\n return;\n lastEvent = e; // this is quite racy\n if (hb->flags & HANDLER_RUNNING) {\n auto tmp = mkEvent(e.source, e.value);\n if (hb->pending == NULL) {\n hb->pending = tmp;\n } else {\n int numev = 0;\n auto p = hb->pending;\n for (; p->next; p = p->next)\n numev++;\n if (numev >= 10) {\n xfree(tmp);\n return;\n }\n p->next = tmp;\n }\n } else {\n hb->flags |= HANDLER_RUNNING;\n setupThread(hb->action, fromInt(e.value), hb);\n }\n}\n\nstatic void dispatchEvent(Event &e) {\n startHandler(findBinding(e.source, e.value), e);\n startHandler(findBinding(e.source, DEVICE_EVT_ANY), e);\n}\n\nstatic void wakeFibers() {\n for (;;) {\n pthread_mutex_lock(&eventMutex);\n if (eventHead == NULL) {\n pthread_mutex_unlock(&eventMutex);\n return;\n }\n Event *ev = eventHead;\n eventHead = ev->next;\n if (eventHead == NULL)\n eventTail = NULL;\n pthread_mutex_unlock(&eventMutex);\n\n for (auto thr = allFibers; thr; thr = thr->next) {\n if (thr->waitSource == 0)\n continue;\n if (thr->waitValue != ev->value && thr->waitValue != DEVICE_EVT_ANY)\n continue;\n if (thr->waitSource == ev->source) {\n thr->waitSource = 0;\n } else if (thr->waitSource == DEVICE_ID_NOTIFY && ev->source == DEVICE_ID_NOTIFY_ONE) {\n thr->waitSource = 0;\n break; // do not wake up any other threads\n }\n }\n\n dispatchEvent(*ev);\n delete ev;\n }\n}\n\nstatic void saveStack() {\n auto f = currentFiber;\n if (!f)\n return;\n int sizeNeeded = vmImg->stackTop - f->sp;\n // DMESG(\"save %d %p\", sizeNeeded, f);\n if (!f->stackCopy || sizeNeeded > f->stackCopySize) {\n xfree(f->stackCopy);\n f->stackCopySize = sizeNeeded + 10;\n f->stackCopy = (TValue *)xmalloc(f->stackCopySize * sizeof(TValue));\n // DMESG(\" -> %p\", f->stackCopy);\n }\n memcpy(f->stackCopy, f->sp, sizeNeeded * sizeof(TValue));\n}\n\nstatic void restoreStack() {\n auto f = currentFiber;\n memcpy(f->sp, f->stackCopy, (uint8_t *)vmImg->stackTop - (uint8_t *)f->sp);\n}\n\nstatic void mainRunLoop() {\n FiberContext *f = NULL;\n for (;;) {\n if (panicCode)\n return;\n wakeFibers();\n auto now = current_time_ms();\n auto fromBeg = false;\n if (!f) {\n f = allFibers;\n fromBeg = true;\n }\n while (f) {\n if (f->wakeTime && now >= (int)f->wakeTime)\n f->wakeTime = 0;\n if (!f->wakeTime && !f->waitSource)\n break;\n f = f->next;\n }\n if (f) {\n if (currentFiber != f) {\n saveStack();\n currentFiber = f;\n restoreStack();\n }\n f->pc = f->resumePC;\n f->resumePC = NULL;\n if (f->wakeFn) {\n auto fn = f->wakeFn;\n f->wakeFn = NULL;\n f->r0 = fn(f->wakeFnArg);\n if (f->wakeTime || f->waitSource)\n continue; // we got suspended again\n }\n exec_loop(f);\n if (panicCode)\n return;\n auto n = f->next;\n if (f->resumePC == NULL) {\n if (f->foreverPC) {\n f->resumePC = f->foreverPC;\n f->wakeTime = current_time_ms() + 20;\n // restore stack, as setupThread() does it\n for (int i = 0; i < 5; ++i) {\n if (*--f->sp == TAG_STACK_BOTTOM)\n break;\n }\n if (*f->sp != TAG_STACK_BOTTOM)\n target_panic(PANIC_INVALID_IMAGE);\n } else {\n auto hb = f->handlerBinding;\n if (hb) {\n auto pev = hb->pending;\n if (pev) {\n hb->pending = pev->next;\n setupThread(hb->action, fromInt(pev->value), hb);\n xfree(pev);\n } else {\n f->handlerBinding->flags &= ~HANDLER_RUNNING;\n }\n }\n disposeFiber(f);\n }\n }\n f = n;\n } else if (fromBeg) {\n target_yield();\n }\n }\n}\n\nint allocateNotifyEvent() {\n static volatile int notifyId;\n return ++notifyId;\n}\n\nvoid raiseEvent(int id, int event) {\n auto e = mkEvent(id, event);\n pthread_mutex_lock(&eventMutex);\n if (eventTail == NULL) {\n if (eventHead != NULL)\n oops(51);\n eventHead = eventTail = e;\n } else {\n eventTail->next = e;\n eventTail = e;\n }\n pthread_cond_broadcast(&newEventBroadcast);\n pthread_mutex_unlock(&eventMutex);\n}\n\nDLLEXPORT void pxt_raise_event(int id, int event) {\n raiseEvent(id, event);\n}\n\nvoid registerWithDal(int id, int event, Action a, int flags) {\n // TODO support flags\n setBinding(id, event, a);\n}\n\nuint32_t afterProgramPage() {\n return 0;\n}\n\nchar **initialArgv;\n\nvoid screen_init();\nvoid initKeys();\nvoid target_startup();\n\nvoid initRuntime() {\n current_time_ms();\n target_startup();\n\n setupThread((TValue)vmImg->entryPoint);\n\n target_init();\n screen_init();\n initKeys();\n\n DMESG(\"start main loop\");\n\n mainRunLoop();\n systemReset();\n}\n\nvoid *gcAllocBlock(size_t sz) {\n#ifdef PXT_ESP32\n void *r = xmalloc(sz);\n#else\n static uint8_t *currPtr = (uint8_t *)GC_BASE;\n sz = (sz + GC_PAGE_SIZE - 1) & ~(GC_PAGE_SIZE - 1);\n#if defined(PXT64) || defined(__MINGW32__)\n if (!gcBase) {\n gcBase = (uint8_t *)xmalloc(1 << PXT_VM_HEAP_ALLOC_BITS);\n currPtr = gcBase;\n }\n void *r = currPtr;\n if ((uint8_t *)currPtr - gcBase > (1 << PXT_VM_HEAP_ALLOC_BITS) - (int)sz)\n soft_panic(20);\n#else\n void *r = mmap(currPtr, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);\n if (r == MAP_FAILED) {\n DMESG(\"mmap %p failed; err=%d\", currPtr, errno);\n target_panic(PANIC_INTERNAL_ERROR);\n }\n#endif\n currPtr = (uint8_t *)r + sz;\n#endif\n\n if (isReadOnly((TValue)r)) {\n DMESG(\"mmap returned read-only address: %p\", r);\n target_panic(PANIC_INTERNAL_ERROR);\n }\n return r;\n}\n\nvoid gcProcessStacks(int flags) {\n int cnt = 0;\n for (auto f = allFibers; f; f = f->next) {\n TValue *end, *ptr;\n if (f == currentFiber) {\n end = vmImg->stackTop;\n ptr = f->sp;\n } else {\n end = f->stackCopy + (vmImg->stackTop - f->sp);\n ptr = f->stackCopy;\n }\n gcProcess((TValue)f->currAction);\n gcProcess((TValue)f->r0);\n if (flags & 2)\n DMESG(\"RS%d:%p/%d\", cnt++, ptr, end - ptr);\n // VLOG(\"mark: %p - %p\", ptr, end);\n while (ptr < end) {\n gcProcess(*ptr++);\n }\n }\n}\n\n#define MAX_RESET_FN 32\nstatic reset_fn_t resetFunctions[MAX_RESET_FN];\n\nvoid registerResetFunction(reset_fn_t fn) {\n for (int i = 0; i < MAX_RESET_FN; ++i) {\n if (!resetFunctions[i]) {\n resetFunctions[i] = fn;\n return;\n }\n }\n\n target_panic(PANIC_INTERNAL_ERROR);\n}\n\nvoid systemReset() {\n#ifdef PXT_ESP32\n esp_restart();\n#else\n if (!panicCode)\n panicCode = -1;\n\n dmesg(\"TARGET RESET\");\n\n gcFreeze();\n\n for (int i = 0; i < MAX_RESET_FN; ++i) {\n auto fn = resetFunctions[i];\n if (fn)\n fn();\n }\n\n coreReset(); // clears handler bindings\n\n currentFiber = NULL;\n while (allFibers) {\n disposeFiber(allFibers);\n }\n\n // this will consume all events, but won't dispatch anything, since all listener maps are empty\n wakeFibers();\n\n // mark all GC memory as free\n gcReset();\n\n pthread_exit(NULL);\n#endif\n}\n\n} // namespace pxt\n",
@@ -1605,19 +1605,19 @@ var pxtTargetBundle = {
1605
1605
  "corgio": {
1606
1606
  "README.md": "# Corgio\n\nA small wrapper to help in creating a Corgi based platformer.",
1607
1607
  "corgio.ts": "/**\n* Sprite Wrapper for a Corgi Platformer\n*/\n//% weight=100 color=#d2b48c icon=\"\\uf1b0\"\n//% groups='[\"Create\", \"Movement\", \"Speak\", \"Properties\"]'\nnamespace corgio {\n export enum CorgiFlags {\n None = 0,\n HorizontalMovement = 1 << 0,\n VerticalMovement = 1 << 1,\n UpdateSprite = 1 << 2,\n CameraFollow = 1 << 3,\n All = ~(~0 << 4)\n }\n\n export let _corgi_still: Image[] = [\n img`\n . . 4 . . . 4 . .\n . 4 f 4 d 4 f 4 .\n . 4 f 4 4 4 f 4 .\n . e 4 d 4 d 4 4 .\n . 4 4 f 4 f 4 f .\n d e 4 4 4 4 4 e d\n d d 4 e d e 4 d d\n `,\n img`\n . . 4 . . . 4 . .\n . 4 f 4 d 4 f 4 .\n . 4 f 4 4 4 f 4 .\n . e 4 d 4 d 4 4 .\n . 4 4 f e f 4 f .\n . e 4 4 4 4 4 e .\n d e d 4 e 4 d e d\n d d d e d e d d d\n `,\n img`\n . . 4 . . . 4 . .\n . 4 f 4 d 4 f 4 .\n . 4 f 4 4 4 f 4 .\n . e 4 d 4 d 4 4 .\n . 4 4 f 4 f 4 f .\n . e 4 4 4 4 4 e .\n d e d 4 a 4 d e d\n d d d e d e d d d\n `,\n img`\n . . 4 . . . 4 . .\n . 4 f 4 d 4 f 4 .\n . 4 f 4 4 4 f 4 .\n . e 4 d 4 d 4 4 .\n . 4 4 f 4 f 4 f .\n . e 4 4 4 4 4 e .\n d e d 4 a 4 d e d\n d d d e a e d d d\n `,\n img`\n . . 4 . . . 4 . .\n . 4 f 4 d 4 f 4 .\n . 4 f 4 4 4 f 4 .\n . e 4 d 4 d 4 4 .\n . 4 4 f 4 f 4 f .\n . e 4 4 4 4 4 e .\n d e d 4 a 4 d e d\n d d d e d e d d d\n `,\n img`\n . . 4 . . . 4 . .\n . 4 f 4 d 4 f 4 .\n . 4 f 4 4 4 f 4 .\n . e 4 d 4 d 4 4 .\n . 4 4 f 4 f 4 f .\n . e 4 4 4 4 4 e .\n d e d 4 4 4 d e d\n d d d e d e d d d\n `,\n ];\n\n export let _corgi_left: Image[] = [\n img`\n . . . . . . . . . . . . . . . .\n . . 4 . . . 4 . . . . . . . . .\n . 4 f 4 d 4 f 4 . . . . . . . .\n . 4 f 4 4 4 f 4 . . . . . . . .\n . 4 4 d 4 d 4 4 . . . . . . . .\n . e 4 f 4 f 4 e . . . . e 4 f .\n . e 4 4 4 4 4 4 d . . . e 4 f .\n f d 4 4 4 4 4 d d e e e 4 4 4 .\n . 4 d d d 4 f d 4 4 4 4 4 4 . .\n . . 4 d d f f d d 4 4 4 4 4 4 .\n . . . . . d d d 4 4 f 4 f 4 4 .\n . . . . . . d 4 d 4 f f f 4 d d\n . . . . . . f . . . . . . . d f\n `,\n img`\n . . . . . . . . . . . . . . . .\n . . 4 . . . 4 . . . . . . . . .\n . 4 f 4 d 4 f 4 . . . . . . . .\n . 4 f 4 4 4 f 4 . . . . . . . .\n . 4 4 d 4 d 4 4 . . . . e 4 f .\n . e 4 f 4 f 4 e . . . . e 4 f .\n . e 4 4 4 4 4 4 d e e e 4 4 4 .\n f d 4 4 4 4 4 d d 4 4 4 4 4 . .\n . 4 d d d 4 f d 4 4 4 4 4 4 4 .\n . . 4 d d f f d d 4 f 4 f 4 4 .\n . . . . . d d d 4 d f f f 4 d d\n . . . . . . d 4 d . . . . . d f\n . . . . . . f . . . . . . . . .\n `,\n img`\n . . 4 . . . 4 . . . . . . . . .\n . 4 f 4 d 4 f 4 . . . . . . . .\n . 4 f 4 4 4 f 4 . . . . . . . .\n . 4 4 d 4 d 4 4 . . . . e 4 f .\n . e 4 f 4 f 4 e . . . . e 4 f .\n . e 4 4 4 4 4 4 d e e e 4 4 4 .\n f d 4 4 4 4 4 d d 4 4 4 4 4 . .\n . 4 d d d 4 f d 4 4 4 4 4 4 4 .\n . . 4 d d f f d d 4 f 4 f 4 4 .\n . . . . d d d 4 4 d f f f 4 d d\n . . . f d 4 . . . . . . . . d f\n . . . . f . . . . . . . . . . .\n `,\n img`\n . . 4 . . . 4 . . . . . . . . .\n . 4 f 4 d 4 f 4 . . . . . . . .\n . 4 f 4 4 4 f 4 . . . . . . . .\n . 4 4 d 4 d 4 4 . . . . e 4 f .\n . e 4 f 4 f 4 e . . . . e 4 f .\n . e 4 4 4 4 4 4 d e e e 4 4 4 .\n f d 4 4 4 4 4 d d 4 4 4 4 4 . .\n . 4 d d d 4 f d 4 4 4 4 4 4 . .\n . . 4 d d f f d d 4 f 4 f 4 . .\n . . . . d d d 4 4 d f f f 4 d .\n . . . f d 4 . . . . . . 4 d d .\n . . . . . . . . . . . . . f . .\n `,\n img`\n . . 4 . . . 4 . . . . . . . . .\n . 4 f 4 d 4 f 4 . . . . . . . .\n . 4 f 4 4 4 f 4 . . . . . . . .\n . 4 4 d 4 d 4 4 . . . . e 4 f .\n . e 4 f 4 f 4 e . . . . e 4 f .\n . e 4 4 4 4 4 4 d e e e 4 4 4 .\n f d 4 4 4 4 4 d d 4 4 4 4 4 . .\n . 4 d d d 4 f d 4 4 4 4 4 4 . .\n . . 4 d d f f d d 4 f 4 f 4 . .\n . . . . d 4 d 4 4 d f f f 4 d .\n . . . . d 4 . . . . . . 4 d d .\n . . . . . f . . . . . . . f . .\n `\n ];\n\n export let _corgi_right: Image[] = reflect(_corgi_left);\n\n /**\n * Creates a new dart from an image and kind\n * @param kind the kind to make the corgi\n * @param x optional initial x position, eg: 10\n * @param y optional initial y position, eg: 70\n */\n //% blockId=corgiCreate block=\"corgi of kind %kind=spritekind || at x %x y %y\"\n //% expandableArgumentMode=toggle\n //% inlineInputMode=inline\n //% blockSetVariable=myCorg\n //% weight=100\n //% group=\"Create\"\n export function create(kind: number,\n x: number = 10,\n y: number = 70): Corgio {\n return new Corgio(kind, x, y);\n }\n\n // Round input towards 0; 1.4 becomes 1.0, -0.4 becomes 0.0\n export function roundTowardsZero(input: number): number {\n return Math.floor(input) + input < 0 ? 1 : 0;\n }\n\n // Normalize input number to 0, 1, or -1\n export function normalize(input: number): number {\n return input ? input / Math.abs(input) : 0;\n }\n\n // Set the animation for looking right to be the opposite of looking left\n export function reflect(input: Image[]): Image[] {\n let output: Image[] = [];\n for (let i: number = 0; i < input.length; i++) {\n let nextImage = input[i].clone();\n nextImage.flipX();\n output.push(nextImage);\n }\n return output;\n }\n}\n\n/**\n * A Corgi Platformer\n **/\n//% blockNamespace=corgio color=\"#d2b48c\" blockGap=8\nclass Corgio extends sprites.ExtendableSprite {\n private stillAnimation: Image[];\n private _leftAnimation: Image[];\n private _rightAnimation: Image[];\n\n //% group=\"Properties\" blockSetVariable=\"myCorg\"\n //% blockCombine block=\"horizontal speed\"\n maxMoveVelocity: number;\n //% group=\"Properties\" blockSetVariable=\"myCorg\"\n //% blockCombine block=\"gravity\"\n gravity: number;\n //% group=\"Properties\" blockSetVariable=\"myCorg\"\n //% blockCombine block=\"jump speed\"\n jumpVelocity: number;\n //% group=\"Properties\" blockSetVariable=\"myCorg\"\n //% blockCombine block=\"max jumps in a row\"\n maxJump: number;\n //% group=\"Properties\" blockSetVariable=\"myCorg\"\n //% blockCombine block=\"rate horizontal movement is slowed\"\n decelerationRate: number;\n\n private controlFlags: number;\n private initJump: boolean;\n private releasedJump: boolean;\n private count: number;\n private touching: number;\n private remainingJump: number;\n private script: string[];\n\n public constructor(kind: number, x: number, y: number) {\n super(corgio._corgi_still[0], kind);\n this.maxMoveVelocity = 70;\n this.gravity = 300;\n this.jumpVelocity = 125;\n\n this.initJump = true;\n this.releasedJump = true;\n this.maxJump = 2;\n this.count = 0;\n this.touching = 2;\n this.remainingJump = this.maxJump;\n this.script = [\n \"bark\"\n ];\n\n this.controlFlags = corgio.CorgiFlags.None;\n\n this.stillAnimation = corgio._corgi_still;\n this._leftAnimation = corgio._corgi_left;\n this._rightAnimation = corgio._corgi_right;\n\n this.setFlag(SpriteFlag.StayInScreen, true);\n this.ay = this.gravity;\n this.x = x;\n this.y = y;\n }\n\n /**\n * Get the Corgio's sprite\n */\n //% group=\"Properties\"\n //% blockId=corgSprite block=\"%corgio(myCorg) sprite\"\n //% weight=8\n //% deprecated=true\n get sprite(): Sprite {\n return this;\n }\n\n /**\n * Make the character move in the direction indicated by the left and right arrow keys.\n */\n //% group=\"Movement\"\n //% blockId=horizontalMovement block=\"make %corgio(myCorg) move left and right with arrow keys || %on=toggleOnOff\"\n //% weight=100 blockGap=5\n horizontalMovement(on: boolean = true): void {\n this.updateFlags(on, corgio.CorgiFlags.HorizontalMovement);\n\n game.onUpdate(() => {\n if (!(this.controlFlags & corgio.CorgiFlags.HorizontalMovement)) return;\n\n let dir: number = controller.dx();\n\n this.vx = dir ? corgio.normalize(dir) * this.maxMoveVelocity :\n corgio.roundTowardsZero(this.vx * this.decelerationRate);\n })\n }\n\n /**\n * Make the character jump when the up arrow key is pressed, and grab onto the wall when falling.\n */\n //% group=\"Movement\"\n //% blockId=verticalMovement block=\"make %corgio(myCorg) jump if up arrow key is pressed || %on=toggleOnOff\"\n //% weight=100 blockGap=5\n verticalMovement(on: boolean = true): void {\n this.updateFlags(on, corgio.CorgiFlags.VerticalMovement);\n\n controller.up.onEvent(ControllerButtonEvent.Released, () => {\n this.releasedJump = true;\n })\n\n game.onUpdate(() => {\n if (!(this.controlFlags & corgio.CorgiFlags.VerticalMovement)) return;\n\n if (controller.up.isPressed()) {\n if (this.contactLeft() && controller.right.isPressed()\n || this.contactRight() && controller.left.isPressed()) {\n this.remainingJump = Math.max(this.remainingJump + 1, this.maxJump);\n }\n this.jumpImpulse();\n }\n\n if ((this.contactLeft() && controller.left.isPressed()\n || this.contactRight() && controller.right.isPressed())\n && this.vy > - 10) {\n this.ay = this.gravity >> 2;\n } else {\n this.ay = this.gravity;\n }\n\n if (this.contactBelow()) {\n if (this.initJump) {\n this.remainingJump = this.maxJump;\n }\n this.initJump = true;\n }\n })\n }\n\n /**\n * Set camera to follow corgio horizontally, while keeping the screen centered vertically.\n */\n //% group=\"Movement\"\n //% blockId=followCorgi block=\"make camera follow %corgio(myCorg) left and right || %on=toggleOnOff\"\n //% weight=90 blockGap=5\n cameraFollow(on: boolean = true): void {\n this.updateFlags(on, corgio.CorgiFlags.CameraFollow);\n\n game.onUpdate(() => {\n if (this.controlFlags & corgio.CorgiFlags.CameraFollow) {\n scene.centerCameraAt(this.x, screen.height >> 1);\n }\n })\n }\n\n /**\n * Make the character change sprites when moving.\n */\n //% group=\"Movement\"\n //% blockId=updateSprite block=\"change image when %corgio(myCorg) is moving || %on=toggleOnOff\"\n //% weight=100 blockGap=5\n updateSprite(on: boolean = true): void {\n this.updateFlags(on, corgio.CorgiFlags.UpdateSprite);\n game.onUpdate(() => {\n if (!(this.controlFlags & corgio.CorgiFlags.UpdateSprite)) return;\n\n this.count++;\n\n if (this.vx == 0) {\n this.setImage(this.pickNext(this.stillAnimation, 6));\n } else if (this.vx < 0) {\n this.setImage(this.pickNext(this._leftAnimation));\n } else {\n this.setImage(this.pickNext(this._rightAnimation));\n }\n })\n }\n\n /**\n * Add new phrase for the character to bark\n * @param input phrase to add to script, eg: \"bark\"\n */\n //% group=\"Speak\"\n //% blockId=addScript block=\"teach %corgio(myCorg) the word %input\"\n //% weight=95 blockGap=5\n addToScript(input: string): void {\n this.script.push(input);\n }\n\n /**\n * Have the character say one of the phrases in the script at random\n */\n //% group=\"Speak\"\n //% blockId=bark block=\"make %corgio(myCorg) bark!\"\n //% weight=95 blockGap=5\n bark(): void {\n this.say(Math.pickRandom(this.script), 250);\n }\n\n private jumpImpulse() {\n if (this.remainingJump > 0 && this.releasedJump) {\n this.releasedJump = false;\n if (this.initJump) {\n this.vy = -1 * this.jumpVelocity;\n this.initJump = false;\n } else {\n this.vy = Math.clamp(\n (-4 * this.jumpVelocity) / 3,\n -30,\n this.vy - this.jumpVelocity\n );\n }\n this.remainingJump--;\n }\n }\n\n private updateFlags(on: boolean, flag: corgio.CorgiFlags): void {\n if (on) this.controlFlags |= flag;\n else this.controlFlags &= corgio.CorgiFlags.All ^ flag;\n }\n\n private pickNext(input: Image[], state: number = 3): Image {\n return input[(this.count / state) % input.length];\n }\n\n private contactLeft(): boolean {\n let screenEdge = game.currentScene().camera.offsetX;\n return this.left - screenEdge <= this.touching\n || this.isHittingTile(CollisionDirection.Left);\n }\n\n private contactRight(): boolean {\n let screenEdge = screen.width + game.currentScene().camera.offsetX;\n return screenEdge - this.right <= this.touching\n || this.isHittingTile(CollisionDirection.Right);\n }\n\n private contactBelow(): boolean {\n let screenEdge = screen.height + game.currentScene().camera.offsetY;\n return screenEdge - this.bottom <= this.touching\n || this.isHittingTile(CollisionDirection.Bottom);\n }\n}\n",
1608
- "pxt.json": "{\n \"name\": \"corgio\",\n \"description\": \"A Corgi platformer\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"corgio.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 79,\n \"icon\": \"/static/libs/corgio.png\"\n}\n"
1608
+ "pxt.json": "{\n \"name\": \"corgio\",\n \"description\": \"A Corgi platformer\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"corgio.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 79,\n \"icon\": \"/static/libs/corgio.png\"\n}\n"
1609
1609
  },
1610
1610
  "darts": {
1611
1611
  "README.md": "# Darts\n\nA small wrapper for projecting a path.",
1612
1612
  "darts.ts": "/**\n* A dart with path prediction\n*/\n//% weight=100 color=#6699CC icon=\"\\uf140\"\n//% groups='[\"Create\", \"Actions\", \"Properties\"]'\nnamespace darts {\n /**\n * Creates a new dart from an image and kind\n * @param img the image for the sprite\n * @param kind the kind to make the dart\n * @param x optional initial x position, eg: 10\n * @param y optional initial y position, eg: 110\n */\n //% blockId=dartsCreate block=\"dart %img=screen_image_picker of kind %kind=spritekind || at x %x y %y\"\n //% expandableArgumentMode=toggle\n //% inlineInputMode=inline\n //% blockSetVariable=myDart\n //% weight=100\n //% group=\"Create\"\n export function create(img: Image,\n kind: number,\n x: number = 10,\n y: number = 110): Dart {\n return new Dart(img, kind, x, y);\n }\n\n /**\n * Convert degrees to radians\n * @param degree to convert\n * @return converted value in radians\n */\n export function degreeToRadian(degree: number): number {\n return degree * Math.PI / 180;\n }\n\n /**\n * Evaluate the x component of a given vector\n * @param degree angle of vector\n * @param magnitude magnitude of vector\n * @return x component of vector\n */\n export function xComponent(degree: number, magnitude: number): number {\n return magnitude * Math.cos(degreeToRadian(degree));\n }\n\n /**\n * Evaluate the y component of a given vector\n * @param degree angle of vector\n * @param magnitude magnitude of vector\n * @return y component of vector\n */\n export function yComponent(degree: number, magnitude: number): number {\n return -magnitude * Math.sin(degreeToRadian(degree));\n }\n}\n\n/**\n * A dart\n **/\n//% blockNamespace=darts color=\"#6699CC\" blockGap=8\nclass Dart extends sprites.ExtendableSprite {\n private renderable: scene.Renderable;\n\n private controlKeys: boolean;\n private trace: boolean;\n\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"angle\"\n //% weight=8\n public angle: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"power\"\n //% weight=8\n public pow: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"tracing time (seconds)\"\n //% weight=8\n public iter: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"trace color\"\n //% weight=8\n public traceColor: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"gravity\"\n //% weight=8\n public gravity: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"wind\"\n //% weight=8\n public wind: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"angle adjust rate\"\n //% weight=8\n public angleRate: number;\n //% group=\"Properties\" blockSetVariable=\"myDart\"\n //% blockCombine block=\"wind\"\n //% weight=8\n public powerRate: number;\n\n public constructor(img: Image,\n kind: number,\n x: number,\n y: number) {\n super(img, kind);\n this.x = x;\n this.y = y;\n\n this.gravity = 20;\n this.pow = 50;\n this.angle = 10;\n this.angleRate = 1;\n this.powerRate = 1;\n this.iter = 3;\n this.wind = 0;\n\n this.renderable = scene.createRenderable(-0.5, (target, camera) => {\n let xComp = darts.xComponent(this.angle, this.pow);\n let yComp = darts.yComponent(this.angle, this.pow);\n let xOffset = camera.offsetX;\n let yOffset = camera.offsetY;\n\n for (let i: number = 0.1; i < this.iter; i += i / 5) {\n let x = this.x + i * xComp + (i ** 2) * this.wind / 2;\n let y = this.y + i * yComp + (i ** 2) * this.gravity / 2;\n target.setPixel(\n x - xOffset,\n y - yOffset,\n this.traceColor\n );\n }\n }, () => !this.ay && this.trace);\n\n this.controlKeys = false;\n this.trace = false;\n this.traceColor = 1;\n }\n\n /**\n * NO LONGER NECESSARY -- the dart is now a sprite by itself.\n * Gets the dart's sprite.\n */\n //% group=\"Properties\"\n //% blockId=dartSprite block=\"%dart(myDart) sprite\"\n //% weight=8\n //% deprecated=true\n get sprite(): Sprite {\n return this;\n }\n\n /**\n * Set whether to show the trace for the estimated path\n * @param on whether to turn on or off this feature, eg: true\n */\n //% blockId=setTrace block=\"trace %dart(myDart) path estimate || %on=toggleOnOff\"\n //% weight=50\n //% group=\"Actions\"\n public setTrace(on: boolean = true): void {\n this.trace = on;\n }\n\n /**\n * Throw the dart with the current settings\n */\n //% blockId=throwDart block=\"throw %dart(myDart)\"\n //% weight=50\n //% group=\"Actions\"\n public throwDart(): void {\n this.vx = darts.xComponent(this.angle, this.pow);\n this.vy = darts.yComponent(this.angle, this.pow);\n this.ay = this.gravity;\n this.ax = this.wind;\n }\n\n /**\n * Stop the dart at the current location\n */\n //% blockId=stopDart block=\"stop %dart(myDart)\"\n //% weight=50\n //% group=\"Actions\"\n public stopDart(): void {\n this.ay = 0;\n this.ax = 0;\n this.vx = 0;\n this.vy = 0;\n }\n\n /**\n * Set whether to control the dart with the arrow keys; left and right\n * to adjust the angle, and up and down to increase / decrease power\n * @param on whether to turn on or off this feature, eg: true\n */\n //% blockId=controlKeys block=\"control %dart(myDart) with arrow keys || %on=toggleOnOff\"\n //% weight=50\n //% group=\"Actions\"\n public controlWithArrowKeys(on: boolean = true): void {\n this.controlKeys = on;\n\n game.onUpdate(() => {\n if (this.controlKeys) {\n this.angle -= controller.dx() * this.angleRate / 5;\n this.pow -= controller.dy() * this.powerRate / 5;\n }\n })\n }\n\n destroy(effect?: effects.ParticleEffect, duration?: number) {\n super.destroy(effect, duration);\n this.renderable.destroy();\n }\n\n /**\n * NO LONGER NECESSARY as this uses renderables now to draw onto the background.\n */\n //% blockId=updateBackground block=\"change %dart(myDart) background to image %img=background_image_picker\"\n //% weight=15\n //% group=\"Properties\"\n //% deprecated=true\n public updateBackground(img: Image): void {\n scene.setBackgroundImage(img);\n }\n}",
1613
- "pxt.json": "{\n \"name\": \"darts\",\n \"description\": \"A sprite with path projection\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"darts.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 78,\n \"icon\": \"/static/libs/darts.png\"\n}\n"
1613
+ "pxt.json": "{\n \"name\": \"darts\",\n \"description\": \"A sprite with path projection\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"darts.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 78,\n \"icon\": \"/static/libs/darts.png\"\n}\n"
1614
1614
  },
1615
1615
  "device": {
1616
1616
  "README.md": "# device\n\nThe core library for fantasy game console target.\n\n",
1617
1617
  "bigFood.jres": "{\n \"*\": {\n \"namespace\": \"sprites.food\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"dataEncoding\": \"base64\"\n },\n \"bigBurger\": \"hwQgACAAAAAAAAAAAO7/AID4//8PAAAAAAAAAO67y+94h75rxg8AAAAAAO5mZrb7dmf/vmb8AAAAAOBrtmZmuy9i+P9t9gAAAAC+tru7ZrbsYob/3WsPAADAu7tEtGtm+yJ2/t+0DwAAvERbS0S0Zvsidu7fvfsAAExEtERERGbGInf/T037AMBERERERERrtixn/+9N6wDARERERLRLZLYsh+//TbsPwERLRERbS7S2LPbu/k20D0y0tUREu0S0tiyG7/5NtA9MtEtERERERLssZu/+TbQPTERERERERES7LHbn/020D0xEREREREREuyx35/9NtA9MRERERERERLQsd+buTUQPRkREu0RERES0LHfm701EDEa7RFtLREREtCx35u9NRAxGW0u0RERERLQsd+juTUQMRrRERERERES0LGfo7k1EDEZEREREtEtEtCxm7v5NRAxgRERLRLS1RLQsZu/+TUQOYES0tUREu0S0LHb//k1EDmBEREtEREREtCx37v9N5AAARkRERERERMQiZ+5PTeQAAEZEtEtERET0Ivfu3kvkAACwRLS1REREy3L37t5EDgAAAEtEu0RERCxi/++9RA4AAABgRERERLQsZv++S+QAAAAAAOZERLT7dob/u2TuAAAAAAAA7rvL73hnvmbmDgAAAAAAAADu/wCI+P/vDgAAAA==\",\n \"bigDrumstick\": \"hwQgACAAAAAAAAAAIiIiAgAAAAAAAAAAAAAAIru7uyICAAAAAAAAAAAAILu7u7u74gAAAAAAAAAAAEJEu0S0u+sOAAAAAAAAACBERERLRLvrDgAAAAAAAABCRERERES0u+4AAAAAAAAAQkREREREtLvuAAAAAAAAsEREREREtES77g4AAAAAALBERERERLRLu+sOAAAAAACwRERERES0u7vrDgAAAAAAS0RERERERLS76w4AAAAAAEtERERERES7tCsOAAAAAABLTUREREREu0Qr4gAAAAAAS91ERERERERLKyIAAAAAAEvdREREREREu7siDgAAAABL1E1ERERERLu7Kw4AAAAAsNRNRERERES0RLsCAAAAALBE3URERERERES06wAAAAAAS0RNRERERES7tOsAAAAAAOBLREREREREtLvrAAAAAAAAvru7RERERLS76wAAAAAAAOC+u0tEtEREu+4AAAAAAAAA4O67RLtLtLvOAAAAAAAAAAAA7u7uu7vu2wwAAAAAAAAAAAAAAO7uzt3NAAAAAAAAAAAAAAAAAADb0cvMAAAAAAAAAAAAAAAAsBERvQwAAAAAAAAAAAAAAAAbEREMAAAAAAAAAAAAAAAAG9EdDAAAAAAAAAAAAAAAANvRywAAAAAAAAAAAAAAAAC7EQwAAAAAAAAAAAAAAAAAsMwAAA==\",\n \"bigHam\": \"hwQgACAAAAAAAAAAACAiIiLu7u4AAAAAAAAAACAy3RERERE97gAAAAAAACAyHTEzMzMz3T0OAAAAAAAyER0zMzMzMzPd4wAAAAAgEz3T0TMzMzMz0z0OAAAAMjEzM93dPTMzMzMdDgAAINMxMzMzMz0zMzMzE+0AADIdMzMzMzPdHTEzMxPhAADSMTMzMzMz3dEdMzMTvQ4g0zMzMzMzMxM93TEzHTMOINMzMzMzMzMTM9PR09EzDjIdMzMzMzMz3TETPd3TPQ4yET0zMzMz090d0Tsz09EPMhHRPTMzMz0zM7szMzPRDzLRHT3T3d0zMzMzMzMzEQ8y0dPd3TMzMzMzMzMzMzEPshMz0z0zMzMzMzMzM9OxD77TPdM9MzMzMzMzMzPd4w7uMzEzMzMzMzMzMzMz3fsO4DsTMzMzMzMzMzMz3bP+AODuO90zMzMzMzMzHT37/wAA7u473d3d3d0dET3r//4AAODu7rvTERER0bNm/+8PAAAA4E5Eu7tmZmtmu+7vDwAAAABORLRGtES0u+vu/wAAAAAA4E5ERmRGtGvm6w8AAAAAAADuRERGtERmu+sAAAAAAAAA4E5ERmRGu7sOAAAAAAAAAADgTmRGtLvuAAAAAAAAAAAAAOBOS2TmAAAAAAAAAAAAAAAAvmbmDgAAAAAAAAAAAAAAAODuDgAAAAAAAA==\",\n \"bigPizza\": \"hwQgACAAAAAAAAAAAAAAAAAAAAAAu0REAAAAAAAAAAAAAAAAu10VQQAAAAAAAAAAAAAAS11V0eUAAAAAAAAAAAAARtRdXUHlAAAAAAAAAAAAa4dV1R1dBAAAAAAAAAAAu22HJS4dVA4AAAAAAAAAu11VViLiUlQOAAAAAAAAS+Qu1SUiIt7UTQAAAAAAuz0i4tIlIyLeTe4AAAAAQF0lIiJeJTMi3uUAAAAAsFRVJSMiXlUi4tPlAAAAAEtd1SUzIl5V5T5dBADg7k5dVdVVIuJTVVVVVAQA60vrVFXVVu0+VdVVFdQOAL5DtN5VbYfdVVXVXRVUDgC+NENLVWWHXVVV1V1BRQAAuzQzRN1VVlVVVdVWQUUAALtLM0PUVVVV7lJlh9XlAABLu0QzRF1VJSIuZYcR7QQAu7REM7RUVSIi4lUW0d1NALBLSzNDu1UyIuJV0VTkTgAAu0QzQ7vUMiPiVUFdDgAAALBLRENETi0iPlVN5QAAAAAAvkQ0tOvU7lMV1OQAAAAAAOBLRETrvt1VUdTtAAAAAAAAu0REtE7d1UXU5AAAAAAAALBLRETr1NVFTQ4AAAAAAAAAu0REu0tE1O0OAAAAAAAAAOBOtLvr1E3uAAAAAAAAAAAA7kS0u+7k7gAAAAAAAAAAAODuu+vu7g4AAAAAAAAAAAAA6+7u7u4AAAAAAA==\",\n \"bigTaco\": \"hwQgACAAAAAAAAAAAAAAAO7u7u7uAAAAAAAAAAAA4O5UVVVVRO4AAAAAAAAA4E5V5e7/5O5UDgAAAAAAQE5VVUTu/+7+TuUAAAAAAERmVuTu5P7v7u/lAAAAAEBVdkbu7u7//v/vVA4AAABUZXdITv7+/v//714OAABAJXJ35k7+//7v/+5ODgAATjJzRIf+/+/uVFVVRQ4A4EQickV35u5UVdXd3d0OAE6GLn5FduZU1U3dVVXdDgBud3dXZGZe1V1VVdVF3Q7gdER3VnTm1V1VVVVVVe0A4HVFZ0Z3Xl1V1VVdVdXtAE5lRWdn59XVVVVUVV3VDgBeZUV3Il5dVVVVVVVVRQ4AXnZEJzNUXVVVVVVFVe0AAG53dybi1VVVVdVVVd0OAABuInfnQtVVXVVV1dVNDgAALjNyZ15dVVVVVVXd7QAAAO4ucmdUXUVV1VXV3Q4AAAAg4mJn1V1V1VVVRe0AAAAA4HZn5tVdVVVV1d3tAAAAAAB4d+bVVVXVVVXdDgAAAAAAeHfm3dVVXV3d7QAAAAAAAGB2591VVd3d3eQAAAAAAABgZ+bdVVXd1N0OAAAAAAAAgHeG3dRV3d3tAAAAAAAAAACIhtTdVdXdDgAAAAAAAAAAAIjY3V3U7QAAAAAAAAAAAAAAQNTd3Q4AAAAAAAAAAAAAAABE7u4AAAAAAAAAAA==\",\n \"bigCake\": \"hwQgACAAAAAAAAAAALC7u7u7u7u7AAAAAAAAAACws1vVO1NVvQAAAAAAAAAA2zNbVbVT3bUAAAAAAAAAsNM9W1W1U1VdCwAAAAAAALDdPVtVNVNVVQsAAAAAAACwPT07VVXTVdULAAAAAAAAOz09u1VVO13VCwAAAAAAsNszPbNVVTtdVb0AAAAAALDTMz2zVVU7VVW9AAAAAACwPTPTs1VVM1VVtQAAAAAA2zMz071VVTVVXbUAAAAAANszM9O9VVU1U1VVCwAAALA9MzPTM1NVvVNVXQsAAACwMzMz0zNbVb1TVV0LAAAAuzMzMzM9W1W1U1VdCwAAADszMzMzPVvVNdtVVbUAALAzMzMzM91bVVXbXVW1AAC7MzMzMzPd21XVO13VtQAAOzMzMzMzPdtV1TtVVbUAADsj7jszMz3bXd07Vd3VC7AzMiK+MzM9u93VM1Xd1QuwM+4i4jMzPaNd1b1d3dULOzPuIuIzMz2jXdW93V1VCzs97iLiMzPdo91dvdvd1b070y4ivjMz06PdXb3b3VW9sDPt7jszM9Oj3d29291VvQCrO90zMzMzvdvdvdvd3a0AAKrT3d0zMz3b3T3b3V2rAAAAqjPd3d3ds93du921owAAAACqOtPdPbO7u7u7M6sAAAAAAKCqO7O7uzMzM7MKAAAAAAAAAKqqqqqqqqqqAA==\",\n \"bigDonut\": \"hwQgACAAAAAAAAAAAAAAu6qqqgAAAAAAAAAAAACwu9Pd3bPuAAAAAAAAAACwO93dbd09uu4AAAAAAAAAO91jNnY4PavrDgAAAAAAsNMzmzh2ONO7uu4AAAAAADs9Y4kzdjjTs7q+DgAAALAzM2M4M2Y70z2r6w4AAAA7NDMzMzMzMzPdo+vrAACwQyUzMzMzMzMjM73q6wAAO0MlMzMzMzMzVDI9uusAADtDNDMzs7szM1QyPbu7DrAzMzPTs6q7MzNE06O0tA6wMzMzPTujOiMzMzNKtLQOYDYz070zqjNCPjMzSrREDmuHM9OzozozQj4zs0q7RA5rhzPTO6ozMyMzM6NEs0QOa4cz0zu6MzMzM9OrRLPkADs2MzO7OzMzM2bdSjRD5AA7MzMzuzMzM2OJPUo0S+QAOzMzMzMzMzOWOD1KNEQOADszMzMzYzgzhjOtRLNEDgCwhjNEM2OHMzPTo0RD5AAAoJY4VDIzdjjTPUo0S+QAAKBjiVQyM2M2M6NEtEQOAAAAOmYjMyMzM6tKREvkAAAAADozMzNCPqtKRLREDgAAAACgMzMzQr5KRERL5AAAAAAAoLrT3SOzRES7RA4AAAAAAACqqqq6S7S7ROQAAAAAAAAA4O5LRLTuS+QOAAAAAAAAAADg7u7uu+sOAAAAAAAAAAAAAADu7u4OAAAAAAAAAA==\",\n \"bigIceCream\": \"hwQgACAAAAAAAAAAAAAAAAAAAABERAAAAAAAAAAAAABARERE1V0EAAAAAAAwszMA1N1EVVXdRQAAAACwE9ERS93dVVRV1V0EAAAAOx3REd27XVVFVVXdRQAAANsd0R3R3VtVVVRV1U0AADMzHREdEd2xVVVFVVVNALPd3RMR3RHdEVtVVVRVRTDbEdHREdER3R2xVVVF1UWw3RERHR0RHdEd0VtVRd0EsN0REdHREdER3RFbVdXUBDDRHRHR0R0RHRHdsVXV1AQTER0R0dHdEdERMT1b1U0AExHREREd3RMR3REzW91NABMR0R0RHd09Ed0dMdvdTQATERHdEdHR3RMR3dGz3U0A273b0R3REd3TEd0Rs90EADvbERPdER3RPRHdHb1NAACwHRE90R3dET0d0R0xBAAAMBHd3RMd0R3dE9Ed0QMAABvREdET0RHd3dPRHREDAAAbHRER3REd0d0z0R0RAwAA0xEREd0RHdHdPdEd0QMAABMR3d3dEd0R3T3RHT0AAAAT0R0R3R3REd093REzAAAAE9ET3d0d0RHdvd0xAwAAANMR093dE9HR3bM7AwAAAAAwET3TPRPRMd27AAAAAAAAMBExuzsR3T09CwAAAAAAAAATEbMAM90zuwAAAAAAAAAAMB3RCwC7uwAAAAAAAAAAAAAzuwAAAAAAAAAAAAAAAA==\",\n \"plate\": \"hwQxABgAAAAAAAAAsLu7CwAAAAAAAACw2xERvQsAAAAAAADbEREREb0AAAAAALAdEREREdELAAAAANsRERERERG9AAAAABsRERERERGxAAAAsB0REd0dERHRCwAAsBER3dHdERERCwAA2xHREd3dHRERvQAAGxHd0d3d3RERvQAAGxEd0d3d3R0RsQCwHdEd3RER3RsR0QuwEdERHRER0dsR0QuwEdHRHREREb0REQuwER3REREREb0dEQvbER3dEREREdEbEQvbER3dEREREdEbEb0b0REdEREREREbEb0b0REdERERERHbEb0b0REdERERERG7EbEb0REdERERERG7EbEb0REdERERERG9EbEb0REdERERERG9EbEb0REdERERERG9EbEb0REdERERERG9EbEb0REdERERERG9EbEb0REdERERERG9EbEb0REdERERERG9EbEb0REdERERERHdEbEb0REdERERERHdEbEb0REdERERERHdEb0bER0dEREREREdEb3bER3dEREREdEdEb3bER3dEREREdEdEQuwER3REREREd0dEQuwEdHRHREREb0REQuwEdERHRER0b0R0QuwHdEd3RER3dsR0QsAGxEd0d3d3RsRsQAAGxHd0d3dvR0RvQAA2xHREd3d2xERvQAAsBERHdG7HRERCwAAsB0REd0dERHRCwAAABsRERERERGxAAAAANsRERERERG9AAAAALAdEREREdELAAAAAADbEREREb0AAAAAAACw2xERvQsAAAAAAAAAsLu7CwAAAAA=\"\n}",
1618
1618
  "bigFood.ts": "namespace sprites.food {\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigBurger = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigDrumstick = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigHam = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigPizza = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigTaco = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigCake = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigDonut = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const bigIceCream = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const plate = image.ofBuffer(hex``);\n}\n",
1619
1619
  "ns.ts": "//% color=#8854d0\nnamespace game {\n /**\n * Reset the current game. This is usually equivalent to pressing\n * the reset button to restart the current program\n */\n //% blockId=arcade_game_reset block=\"reset game\"\n //% group=\"Gameplay\" weight=10\n //% help=game/reset\n export function reset() {\n control.reset();\n }\n}\n\n//% color=\"#4b6584\"\nnamespace scene {\n\n}\n\n//% color=\"#cf6a87\"\nnamespace info {\n\n}\n\n//% color=#E30FC0\nnamespace music {\n\n}\n\n//% color=#B09EFF\nnamespace player {\n\n}\n\n//% color=#FF5722 weight=90 advanced=true\nnamespace control {\n\n}\n",
1620
- "pxt.json": "{\n \"name\": \"device\",\n \"description\": \"The fantasy game console library\",\n \"dependencies\": {\n \"hw\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"ns.ts\",\n \"sprites.background.ts\",\n \"sprites.background.jres\",\n \"smallFood.jres\",\n \"smallFood.ts\",\n \"bigFood.jres\",\n \"bigFood.ts\",\n \"sprites.duck.jres\",\n \"sprites.duck.ts\",\n \"sprites.castle.jres\",\n \"sprites.castle.ts\",\n \"sprites.builtin.jres\",\n \"sprites.builtin.ts\",\n \"sprites.dialog.jres\",\n \"sprites.dialog.ts\",\n \"sprites.dungeon.jres\",\n \"sprites.dungeon.ts\",\n \"sprites.space.jres\",\n \"sprites.space.ts\",\n \"sprites.vehicle.ts\",\n \"sprites.vehicle.jres\",\n \"sprites.projectile.ts\",\n \"sprites.projectile.jres\",\n \"sprites.kaiju.ts\",\n \"sprites.kaiju.jres\",\n \"sprites.swamp.ts\",\n \"sprites.swamp.jres\",\n \"sprites.skillmap.ts\",\n \"sprites.skillmap.jres\",\n \"storySprites.ts\",\n \"storySprites.jres\",\n \"startup.ts\",\n \"pxtsnippets.json\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"core\": true,\n \"palette\": [\n \"#000000\",\n \"#ffffff\",\n \"#ff2121\",\n \"#ff93c4\",\n \"#ff8135\",\n \"#fff609\",\n \"#249ca3\",\n \"#78dc52\",\n \"#003fad\",\n \"#87f2ff\",\n \"#8e2ec4\",\n \"#a4839f\",\n \"#5c406c\",\n \"#e5cdc4\",\n \"#91463d\",\n \"#000000\"\n ],\n \"screenSize\": {\n \"width\": 160,\n \"height\": 120\n }\n}\n",
1620
+ "pxt.json": "{\n \"name\": \"device\",\n \"description\": \"The fantasy game console library\",\n \"dependencies\": {\n \"hw\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"ns.ts\",\n \"sprites.background.ts\",\n \"sprites.background.jres\",\n \"smallFood.jres\",\n \"smallFood.ts\",\n \"bigFood.jres\",\n \"bigFood.ts\",\n \"sprites.duck.jres\",\n \"sprites.duck.ts\",\n \"sprites.castle.jres\",\n \"sprites.castle.ts\",\n \"sprites.builtin.jres\",\n \"sprites.builtin.ts\",\n \"sprites.dialog.jres\",\n \"sprites.dialog.ts\",\n \"sprites.dungeon.jres\",\n \"sprites.dungeon.ts\",\n \"sprites.space.jres\",\n \"sprites.space.ts\",\n \"sprites.vehicle.ts\",\n \"sprites.vehicle.jres\",\n \"sprites.projectile.ts\",\n \"sprites.projectile.jres\",\n \"sprites.kaiju.ts\",\n \"sprites.kaiju.jres\",\n \"sprites.swamp.ts\",\n \"sprites.swamp.jres\",\n \"sprites.skillmap.ts\",\n \"sprites.skillmap.jres\",\n \"storySprites.ts\",\n \"storySprites.jres\",\n \"startup.ts\",\n \"pxtsnippets.json\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"core\": true,\n \"palette\": [\n \"#000000\",\n \"#ffffff\",\n \"#ff2121\",\n \"#ff93c4\",\n \"#ff8135\",\n \"#fff609\",\n \"#249ca3\",\n \"#78dc52\",\n \"#003fad\",\n \"#87f2ff\",\n \"#8e2ec4\",\n \"#a4839f\",\n \"#5c406c\",\n \"#e5cdc4\",\n \"#91463d\",\n \"#000000\"\n ],\n \"screenSize\": {\n \"width\": 160,\n \"height\": 120\n }\n}\n",
1621
1621
  "pxtsnippets.json": "[\n {\n \"name\": \"Create a Sprite\",\n \"namespace\": \"sprites\",\n \"group\": \"Create\",\n \"label\": \"Create a sprite...\",\n \"outputType\": \"blocks\",\n \"initialOutput\": \"let $spriteName = sprites.create($spriteImage, $spriteKind)\",\n \"questions\": [\n {\n \"title\": \"Draw your sprite\",\n \"inputs\": [\n {\n \"answerToken\": \"spriteImage\",\n \"type\": \"spriteEditor\",\n \"defaultAnswer\": \"img`\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n. . . . . . . . . . . . . . . .\\n`\"\n }\n ],\n \"hint\": \"Sprites are 2D characters and objects used in all MakeCode Arcade games. Click and drag to draw your own sprite.\",\n \"goto\": {\n \"question\": 1\n }\n },\n {\n \"title\": \"Name your sprite\",\n \"inputs\": [\n {\n \"answerToken\": \"spriteName\",\n \"defaultAnswer\": \"mySprite\",\n \"type\": \"variableName\"\n }\n ],\n \"output\": \"\",\n \"hint\": \"Naming sprites is important because you can use the name to refer to your sprite elsewhere in your program.\",\n \"goto\": {\n \"question\": 2\n }\n },\n {\n \"title\": \"What kind of sprite is this?\",\n \"inputs\": [\n {\n \"answerToken\": \"spriteKind\",\n \"defaultAnswer\": \"SpriteKind.Player\",\n \"type\": \"dropdown\",\n \"options\": {\n \"SpriteKind.Player\": \"Player\",\n \"SpriteKind.Enemy\": \"Enemy\",\n \"SpriteKind.Food\": \"Food\"\n }\n }\n ],\n \"goto\": {\n \"question\": 3,\n \"parameters\": [\n {\n \"answer\": \"SpriteKind.Player\",\n \"token\": \"spriteKind\",\n \"question\": 4\n }\n ]\n },\n \"hint\": \"The kind of sprite is used when two sprites overlap.\\n\\nIf none of the kinds match your sprite, just select \\\"Player\\\".\"\n },\n {\n \"title\": \"Where should your sprite appear?\",\n \"inputs\": [\n {\n \"label\": \"X (horizontal):\",\n \"defaultAnswer\": 80,\n \"answerToken\": \"xLocation\",\n \"type\": \"number\",\n \"min\": 0,\n \"max\": 160\n },\n {\n \"label\": \"Y (vertical):\",\n \"defaultAnswer\": 60,\n \"answerToken\": \"yLocation\",\n \"type\": \"number\",\n \"min\": 0,\n \"max\": 120\n }\n ],\n \"output\": \"$spriteName.setPosition($xLocation,$yLocation)\",\n \"hint\": \"This location is where your sprite will be when the game begins. 0 for X means the left of the screen, 0 for Y means the top of the screen.\"\n },\n {\n \"title\": \"Do you want to control your player with direction buttons?\",\n \"inputs\": [\n {\n \"type\": \"yesno\",\n \"defaultAnswer\": false,\n \"answerToken\": \"$moveWithButtons\"\n }\n ],\n \"output\": \"controller.moveSprite($spriteName)\",\n \"outputConditionalOnAnswer\": \"true\",\n \"goto\": {\n \"question\": 3\n },\n \"hint\": \"If you choose \\\"Yes\\\", the direction buttons or \\\"D-Pad\\\" will move your player left, right, up and down respectively.\"\n }\n ]\n }\n]\n",
1622
1622
  "smallFood.jres": "{\n \"*\": {\n \"namespace\": \"sprites.food\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"dataEncoding\": \"base64\"\n },\n \"smallBurger\": \"hwQQABAAAAAAAO4OiO7uAADsu+t3xusOwExEuy5mvg7AREVE7nLoy7xERETrYsjLTERERORizMRMREVE5HLsxEtERETkcujES0VEVORy6ORLRERE5GLs5EtERETkYuzku1REROtyzOSwRFRE7mLo5LBLRLQuxr4OAOxL63bM6w4AAOwOiO7uAA==\",\n \"smallApple\": \"hwQQABAAAAAAAMDMzAwAAADA7O7u7gIAAOzu7u7uLgAA7u4iIuLuAuDuLiIiIuIC4O4iIiIiIi7g7i4iIiIiLs7MLCIiIiLkfGcsIiIiIuR37iIiIiIi5ODiRCIiIkLi4CJVJCIiQg4ALlQkIiIkDgAuIiIiROIAAOAuIiLiDgAAAODu7g4AAA==\",\n \"smallLemon\": \"hwQQABAAAABEC7DMzAAAAFS0S91EzAAAVFVdRdVEDABAVVVVVdXEAEBRVVVFVUQMVFVVVV1FTQxUEVVV1VVEy1QRVVVV3UTEVFFVVVVNRMRUVVVVVU1ExEAVVVVV1UTLQBVRVVVVTcsAVBFVVVVdtABAVRVVVVW1AABEVVVFXUQAAABERMtMBA==\",\n \"smallDrumstick\": \"hwQQABAAAAAAIiIiAAAAACCyuysCAAAAskREtOsAAABCREREuw4AAEtERES7DgAAS0RERLTrAABLTUREtOQAAEtNRES05AAAS9RERLvrAACwRE1Eu+4AAAC7RLTr7gAAAAC77u6+ywwAAAAAANsRwQAAAAAAsNHLAAAAAACw0QwAAAAAAAC7AA==\",\n \"smallHam\": \"hwQQABAAAAAAAAAiIu4OAAAAItPd3eMAACATMTPTPQ4AMtE9MzMT4yATM9MzMxPjIN0zExEz0eMyMTMxE93d4zIxMxExMx3jMj3TMzMzE+My3T0zMzMd6yDTMTMzHbHu4DITERE9u+4A7jszu7vr7gAAvkRERO4OAACwS0S07gAAAAC77u4AAA==\",\n \"smallPizza\": \"hwQQABAAAAAAAAAAAAC7RAAAAAAAu11NAAAAALsjU00AAAC7XSJSTQAAu11XI10EALA9MlVV1QS7SyUiVVfVBEu7NTJVVUUAS7RVVSNTTQBLtFRXIlJNALBES1UjU00AAEvkVFXVBAAAsETuVd0EAAAAS+Te7QAAAACw5O5OAAAAAADu7gQAAA==\",\n \"smallDonut\": \"hwQQABAAAAAAAAC7q6oAAAAAuzMzow4AALAzMzMz6gAA2z0zMzPqDrDdMzMzM7oOsD0zszPTug7bPTOqM9NKDtszozoz00oO2zOjMzOtRA47MzszM61EDjozMzPTSrQOOjMzM61E5ACgMzPdSkTuAKA6M6pE5A4AAKqqRETuAAAAALu77gAAAA==\",\n \"smallCake\": \"hwQQABAAAAAAALC7u7sLAAAAsLM9MwsAAAA7s9XTCwAAADuz1VOzAACwM71VU70AALAzvVVTtQAAOzO9XTM1CwA7Mz1bPdULsO4z01s1VQvgIz7TWzVVC+siPtNaNVWzO+4z09o9Vb07MzPT2r3dvbA6M93avd2tAKA6Pdq9O6sAAKCqqqqqCg==\",\n \"smallIceCream\": \"hwQQABAAAAAAAAAAAEREAAAAM0tEXVUEADARvdTdVUUA0xERvVVdRTDdHRHRW9VFExHRERG91QQTEREdEbHdBNsREdER0dsEM90R0RERSwDT0R0RERFLAB0RHREdEb0AHRHRER0RPQATHRERHdEDABMzG9E7MwAAMDEwMwsAAAAAMwAAAAAAAA==\",\n \"smallStrawberry\": \"hwQQABAAAAAAAADu7u7uDgAA7iIiIu7OAOAiREQk4s4ALkJFIiLuwgAuRCIiIiLOAC4kIkIi4s6AKGJmJiIkzGbod3cmIiLOYIZ3ZyJC4gwAZncmQuLuDABgZyIiIu4MAHZ3Zy7izgBgZ2h35+4MAIAIhnZ3zAAAAACAYGYGAAAAAAAAAAAAAA==\",\n \"smallCherries\": \"hwQQABAAAAAAAODuDAAAAAAALiLCAAAAAOBC4i4MAAAA4CXi7uIAAADgJCLiwgAAAOAiIuLCAAAAyC4iIu4AAABoLCLizswAAGjI7C4i4gxghwDgQiLuzmCHAOAlIu7CdggA4CQi4sJ2iGbIIiLiwnZ2d2YsIu7CdoiIiMgiIgyGCAAAAO7MAA==\",\n \"smallTaco\": \"hwQQABAAAAAAAADg7u5OAAAA4E5VVVUEAABeVczsTkUA4GWGzszuRABeImfoVVXl4GQiZ1VFVeXgZYdYRVVV5E52hlVVRVUOXiJWVFRV5QBeIlRVVVXkAF5nVVRFVQ4A4EZVVVXlAADgRlVFVeQAAABORVVVDgAAAOBUVeUAAAAAAEBEBAAAAA==\"\n}",
1623
1623
  "smallFood.ts": "namespace sprites.food {\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallBurger = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallApple = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallLemon = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallDrumstick = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallHam = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallPizza = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallDonut = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallCake = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallIceCream = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallStrawberry = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallCherries = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._image\n //% tags=\"food\"\n export const smallTaco = image.ofBuffer(hex``);\n}\n",
@@ -1653,19 +1653,19 @@ var pxtTargetBundle = {
1653
1653
  "README.md": "# Edge connector\n\nSupport for 20 pin edge connector.\n\n## Config\n\nPin mapping must be specified in config key section.",
1654
1654
  "device.d.ts": "declare namespace pins {\n /**\n * Pin P0 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P0)\n const P0: PwmPin;\n\n /**\n * Pin P1 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P1)\n const P1: PwmPin;\n\n /**\n * Pin P2 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P2)\n const P2: PwmPin;\n\n /**\n * Pin P3 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P3)\n const P3: AnalogInPin;\n\n /**\n * Pin P3 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P4)\n const P4: AnalogInPin;\n\n /**\n * Pin P5 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P5)\n const P5: DigitalInOutPin;\n\n /**\n * Pin P6 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P6)\n const P6: DigitalInOutPin;\n\n /**\n * Pin P7 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P7)\n const P7: DigitalInOutPin;\n\n /**\n * Pin P8 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P8)\n const P8: DigitalInOutPin;\n\n /**\n * Pin P9 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P9)\n const P9: DigitalInOutPin;\n\n /**\n * Pin P10 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P10)\n const P10: AnalogInPin;\n\n /**\n * Pin P11 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P11)\n const P11: DigitalInOutPin;\n\n /**\n * Pin P12 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P12)\n const P12: DigitalInOutPin;\n\n /**\n * Pin P13 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P13)\n const P13: DigitalInOutPin;\n\n /**\n * Pin P14 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P14)\n const P14: DigitalInOutPin;\n\n /**\n * Pin P15 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P15)\n const P15: DigitalInOutPin;\n\n /**\n * Pin P16 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P16)\n const P16: PwmPin;\n\n /**\n * Pin P19 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P19)\n const P19: DigitalInOutPin;\n\n /**\n * Pin P20 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P20)\n const P20: DigitalInOutPin;\n\n /**\n * Pin P21 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P21)\n const P21: PwmPin;\n\n /**\n * Pin P22 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P22)\n const P22: PwmPin;\n\n /**\n * Pin P23 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P23)\n const P23: PwmPin;\n\n /**\n * Pin P24 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P24)\n const P24: PwmPin;\n\n /**\n * Pin P25 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P25)\n const P25: PwmPin;\n\n /**\n * Pin P26 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P26)\n const P26: PwmPin;\n\n /**\n * Pin P27 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P27)\n const P27: PwmPin;\n\n /**\n * Pin P28 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P28)\n const P28: PwmPin;\n\n /**\n * Pin P29 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P29)\n const P29: PwmPin;\n\n /**\n * Pin P30 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P30)\n const P30: PwmPin;\n\n /**\n * Pin P31 on the edge connector\n */\n //% fixedInstance shim=pxt::lookupPinCfg(CFG_PIN_P31)\n const P31: PwmPin;\n}\n",
1655
1655
  "pinscompat.ts": "// this type alias is required for backward compatibility\n// it gets overriden in microbit (DigitalPin is an enum over there)\nenum DigitalPin {\n P0 = DAL.CFG_PIN_P0,\n P1 = DAL.CFG_PIN_P1,\n P2 = DAL.CFG_PIN_P2,\n P3 = DAL.CFG_PIN_P3,\n P4 = DAL.CFG_PIN_P4,\n P5 = DAL.CFG_PIN_P5,\n P6 = DAL.CFG_PIN_P6,\n P7 = DAL.CFG_PIN_P7,\n P8 = DAL.CFG_PIN_P8,\n P9 = DAL.CFG_PIN_P9,\n P10 = DAL.CFG_PIN_P10,\n P11 = DAL.CFG_PIN_P11,\n P12 = DAL.CFG_PIN_P12,\n P13 = DAL.CFG_PIN_P13,\n P14 = DAL.CFG_PIN_P14,\n P15 = DAL.CFG_PIN_P15,\n P16 = DAL.CFG_PIN_P16,\n P19 = DAL.CFG_PIN_P19,\n P20 = DAL.CFG_PIN_P20\n}\n\nenum AnalogPin {\n P0 = DAL.CFG_PIN_P0,\n P1 = DAL.CFG_PIN_P1,\n P2 = DAL.CFG_PIN_P2,\n P3 = DAL.CFG_PIN_P3,\n P4 = DAL.CFG_PIN_P4,\n P10 = DAL.CFG_PIN_P10,\n P5 = DAL.CFG_PIN_P5,\n P6 = DAL.CFG_PIN_P6,\n P7 = DAL.CFG_PIN_P7,\n P8 = DAL.CFG_PIN_P8,\n P9 = DAL.CFG_PIN_P9,\n P11 = DAL.CFG_PIN_P11,\n P12 = DAL.CFG_PIN_P12,\n P13 = DAL.CFG_PIN_P13,\n P14 = DAL.CFG_PIN_P14,\n P15 = DAL.CFG_PIN_P15,\n P16 = DAL.CFG_PIN_P16,\n P19 = DAL.CFG_PIN_P19,\n P20 = DAL.CFG_PIN_P20\n}\n\nnamespace pins {\n /**\n * Sets the pin pull\n * @param pin \n * @param mode \n */\n //% deprecated=1\n export function setPull(pin: DigitalPin, mode: PinPullMode) {\n const p = pins.pinByCfg(pin);\n if (p)\n p.setPull(mode);\n }\n\n /**\n * Sets the digital pin status\n * @param pin\n * @param value \n */\n //% deprecated=1\n export function digitalWritePin(pin: DigitalPin, value: number) {\n const p = pins.pinByCfg(pin);\n if (p)\n p.digitalWrite(!!value);\n }\n\n /**\n * Reads the pin status\n * @param pin \n */\n //% deprecated=1\n export function digitalReadPin(pin: DigitalPin): number {\n const p = pins.pinByCfg(pin);\n return p && p.digitalRead() ? 1 : 0;\n }\n\n /**\n * Sets the digital pin status\n * @param pin \n * @param value \n */\n //% deprecated=1\n export function analogWritePin(pin: AnalogPin, value: number) {\n const p = pins.pinByCfg(pin) as AnalogOutPin;\n if (p)\n p.analogWrite(value);\n }\n\n /**\n * Reads the pin status\n * @param pin \n */\n //% deprecated=1\n export function analogReadPin(pin: AnalogPin): number {\n const p = pins.pinByCfg(pin) as AnalogInPin;\n if (p)\n return p.analogRead();\n else \n return 0;\n }\n\n /**\n * Make this pin a digital input, and create events where the timestamp is the duration\n * that this pin was either ``high`` or ``low``.\n */\n //% deprecated=1\n export function onPulsed(pin: DigitalPin, pulse: PulseValue, body: () => void): void {\n const p = pins.pinByCfg(pin);\n if (p)\n p.onPulsed(pulse, body);\n }\n\n /**\n * Register code to run when a pin event occurs. \n */\n //% deprecated=1\n export function onEvent(pin: DigitalPin, event: PinEvent, body: () => void): void {\n const p = pins.pinByCfg(pin);\n if (p)\n p.onEvent(event, body);\n }\n\n /**\n * Return the duration of a pulse in microseconds\n * @param name the pin which measures the pulse\n * @param value the value of the pulse (default high)\n * @param maximum duration in micro-seconds\n */\n //% deprecated=1\n export function pulseIn(pin: DigitalPin, value: PulseValue, maxDuration?: number): number {\n const p = pins.pinByCfg(pin);\n if (p)\n return p.pulseIn(value, maxDuration);\n else \n return 0;\n }\n\n export function map(value: number, fromLow: number, fromHigh: number, toLow: number, toHigh: number): number {\n return Math.map(value, fromLow, fromHigh, toLow, toHigh);\n }\n}",
1656
- "pxt.json": "{\n \"name\": \"edge-connector\",\n \"description\": \"20 pin Edge Connector\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"device.d.ts\",\n \"pinscompat.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"requiredCategories\": [\n \"pins\"\n ],\n \"icon\": \"/static/libs/edge-connector.png\"\n}\n"
1656
+ "pxt.json": "{\n \"name\": \"edge-connector\",\n \"description\": \"20 pin Edge Connector\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"device.d.ts\",\n \"pinscompat.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"requiredCategories\": [\n \"pins\"\n ],\n \"icon\": \"/static/libs/edge-connector.png\"\n}\n"
1657
1657
  },
1658
1658
  "esp32": {
1659
1659
  "README.md": "# ESP32\n\nCommunication layer to a accessory ESP32 chip.\n\n> Ported from Adafruit Circuit Python \nhttps://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI.\n\n## Configuration\n\n### Nina-FW over SPI\n\nThe companion firmware is https://github.com/adafruit/nina-fw over SPI.\nThe pins of the main board need to be configured either in the bootloader or using `namespace userconfig { ... }`.\nThe ESP32 pins are listed next to each key below (the number in parenthesis is the pin number on WROOM-32 module).\n\n* ``PIN_WIFI_CS``, ESP32 CS pin mapping, IO5 (29)\n* ``PIN_WIFI_BUSY``, ESP32 BUSY pin mapping, IO33 (9)\n* ``PIN_WIFI_RESET``, ESP32 RESET pin mapping, EN (3)\n* ``PIN_WIFI_GPIO0`` (optional), ESP32 GPIO0 pin mapping, IO0 (25)\n\nThe driver uses the default SPI pins. You can override this behavior by specifying these 3 keys.\n\n* ``PIN_WIFI_MOSI`` (optional), dedicated SPI MOSI pin, IO14 (13)\n* ``PIN_WIFI_MISO`` (optional), dedicated SPI MISO pin, IO23 (37)\n* ``PIN_WIFI_SCK`` (optional), dedicated SPI SCK pin, IO18 (30)\n\n### Expressif AT commands over serial\n\nNot supported yet.\n\n* ``PIN_WIFI_AT_RX``, ESP32 RX pin mapping\n* ``PIN_WIFI_AT_TX``, ESP32 TX pin mapping\n\n## Access Points and passwords\n\nThe module uses access points and password information stored in the device secrets. These secrets can be set programmatically using ``net.updateAccessPoint`` or via the menu items in Arcade (added via the ``net-game`` extension).\n\n> *Friendly reminder:* Do not share .uf2 files or programs with secrets!!\n\n## Example\n\nSee net package readme.",
1660
1660
  "net.ts": "namespace esp32 {\n let _defaultController: net.Controller;\n function defaultController(): net.Controller {\n // cached\n if (_defaultController) return _defaultController;\n\n /*\n // look for ESP32 over serial pins\n const rx = pins.pinByCfg(DAL.CFG_PIN_WIFI_AT_RX);\n const tx = pins.pinByCfg(DAL.CFG_PIN_WIFI_AT_TX);\n if (rx && tx) {\n const dev = serial.createSerial(rx, tx);\n return _defaultController = new ATController(dev);\n }\n */\n\n // look for ESP32 over SPI pins\n const cs = pins.pinByCfg(DAL.CFG_PIN_WIFI_CS)\n const busy = pins.pinByCfg(DAL.CFG_PIN_WIFI_BUSY);\n const reset = pins.pinByCfg(DAL.CFG_PIN_WIFI_RESET);\n const gpio0 = pins.pinByCfg(DAL.CFG_PIN_WIFI_GPIO0); // optional\n if (!!cs && !!busy && !!reset) {\n // grab SPI pins and go\n const mosi = pins.pinByCfg(DAL.CFG_PIN_WIFI_MOSI);\n const miso = pins.pinByCfg(DAL.CFG_PIN_WIFI_MISO);\n const sck = pins.pinByCfg(DAL.CFG_PIN_WIFI_SCK);\n let spi: SPI;\n if (!mosi && !miso && !sck) {\n spi = pins.spi();\n } else if (mosi && miso && sck) {\n spi = pins.createSPI(mosi, miso, sck);\n } else {// SPI misconfigured\n net.log(\"esp32 spi configuration error\");\n control.panic(control.PXT_PANIC.CODAL_HARDWARE_CONFIGURATION_ERROR);\n }\n if (spi)\n return _defaultController = new NinaController(spi, cs, busy, reset, gpio0);\n } else if (!cs && !busy && !reset) {\n return undefined;\n // do nothing, panic later\n } else { // cs,busy,reset misconfigured\n net.log(\"esp32 partially configured\");\n control.panic(control.PXT_PANIC.CODAL_HARDWARE_CONFIGURATION_ERROR);\n }\n\n // no option\n net.log(\"esp32 configuration error\");\n control.panic(control.PXT_PANIC.CODAL_HARDWARE_CONFIGURATION_ERROR);\n return undefined;\n }\n\n // initialize net\n new net.Net(defaultController);\n}",
1661
1661
  "ninacontroller.ts": "namespace esp32 {\n // pylint: disable=bad-whitespace\n const _SET_NET_CMD = 0x10\n const _SET_PASSPHRASE_CMD = 0x11\n const _SET_DEBUG_CMD = 0x1A\n const _GET_TEMP_CMD = 0x1B\n const _GET_CONN_STATUS_CMD = 0x20\n const _GET_IPADDR_CMD = 0x21\n const _GET_MACADDR_CMD = 0x22\n const _GET_CURR_SSID_CMD = 0x23\n const _GET_CURR_RSSI_CMD = 0x25\n const _GET_CURR_ENCT_CMD = 0x26\n const _SCAN_NETWORKS = 0x27\n const _GET_SOCKET_CMD = 0x3F\n const _GET_STATE_TCP_CMD = 0x29\n const _DATA_SENT_TCP_CMD = 0x2A\n const _AVAIL_DATA_TCP_CMD = 0x2B\n const _GET_DATA_TCP_CMD = 0x2C\n const _START_CLIENT_TCP_CMD = 0x2D\n const _STOP_CLIENT_TCP_CMD = 0x2E\n const _GET_CLIENT_STATE_TCP_CMD = 0x2F\n const _DISCONNECT_CMD = 0x30\n const _GET_IDX_RSSI_CMD = 0x32\n const _GET_IDX_ENCT_CMD = 0x33\n const _REQ_HOST_BY_NAME_CMD = 0x34\n const _GET_HOST_BY_NAME_CMD = 0x35\n const _START_SCAN_NETWORKS = 0x36\n const _GET_FW_VERSION_CMD = 0x37\n const _PING_CMD = 0x3E\n const _SEND_DATA_TCP_CMD = 0x44\n const _GET_DATABUF_TCP_CMD = 0x45\n const _SET_ENT_IDENT_CMD = 0x4A\n const _SET_ENT_UNAME_CMD = 0x4B\n const _SET_ENT_PASSWD_CMD = 0x4C\n const _SET_ENT_ENABLE_CMD = 0x4F\n const _SET_PIN_MODE_CMD = 0x50\n const _SET_DIGITAL_WRITE_CMD = 0x51\n const _SET_ANALOG_WRITE_CMD = 0x52\n const _START_CMD = 0xE0\n const _END_CMD = 0xEE\n const _ERR_CMD = 0xEF\n const _REPLY_FLAG = 1 << 7\n const _CMD_FLAG = 0\n export const SOCKET_CLOSED = 0\n export const SOCKET_LISTEN = 1\n export const SOCKET_SYN_SENT = 2\n export const SOCKET_SYN_RCVD = 3\n export const SOCKET_ESTABLISHED = 4\n export const SOCKET_FIN_WAIT_1 = 5\n export const SOCKET_FIN_WAIT_2 = 6\n export const SOCKET_CLOSE_WAIT = 7\n export const SOCKET_CLOSING = 8\n export const SOCKET_LAST_ACK = 9\n export const SOCKET_TIME_WAIT = 10\n export const WL_NO_SHIELD = 0xFF\n export const WL_NO_MODULE = 0xFF\n export const WL_IDLE_STATUS = 0\n export const WL_NO_SSID_AVAIL = 1\n export const WL_SCAN_COMPLETED = 2\n export const WL_CONNECTED = 3\n export const WL_CONNECT_FAILED = 4\n export const WL_CONNECTION_LOST = 5\n export const WL_DISCONNECTED = 6\n export const WL_AP_LISTENING = 7\n export const WL_AP_CONNECTED = 8\n export const WL_AP_FAILED = 9\n\n\n function buffer1(ch: number) {\n const b = control.createBuffer(1)\n b[0] = ch\n return b\n }\n\n export class NinaController extends net.Controller {\n private _socknum_ll: Buffer[];\n private _locked: boolean;\n\n public wasConnected: boolean;\n\n constructor(\n private _spi: SPI,\n private _cs: DigitalInOutPin,\n private _busy: DigitalInOutPin,\n private _reset: DigitalInOutPin,\n private _gpio0: DigitalInOutPin = null\n ) {\n super();\n // if nothing connected, pretend the device is ready -\n // we'll check for timeout waiting for response instead\n this._busy.setPull(PinPullMode.PullDown);\n this._busy.digitalRead();\n this._socknum_ll = [buffer1(0)]\n this._spi.setFrequency(8000000);\n this.reset();\n this._locked = false;\n }\n\n /** \n * Hard reset the ESP32 using the reset pin \n */\n public reset(): void {\n if (this._gpio0)\n this._gpio0.digitalWrite(true);\n this._cs.digitalWrite(true)\n this._reset.digitalWrite(false)\n // reset\n pause(10)\n this._reset.digitalWrite(true)\n // wait for it to boot up\n pause(750)\n if (this._gpio0)\n this._gpio0.digitalRead();\n // make sure SPI gets initialized while the CS is up\n this.spiTransfer(control.createBuffer(1), null)\n net.log('reseted esp32')\n }\n\n private readByte(): number {\n const r = buffer1(0)\n this.spiTransfer(null, r)\n return r[0]\n }\n\n private checkData(desired: number, msg?: string): boolean {\n const r = this.readByte()\n if (r != desired)\n net.fail(`Expected ${desired} but got ${r}; ` + (msg || \"\"))\n return false;\n }\n\n /** Read a byte with a time-out, and if we get it, check that its what we expect */\n private waitSPIChar(desired: number): boolean {\n let times = control.millis()\n while (control.millis() - times < 100) {\n let r = this.readByte()\n if (r == _ERR_CMD) {\n net.log(\"error response to command\")\n return false\n }\n\n if (r == desired) {\n return true\n }\n //net.log(`read char ${r}, expected ${desired}`)\n }\n net.log(\"timed out waiting for SPI char\")\n return false;\n }\n\n /**\n * Wait until the ready pin goes low\n */\n private waitForReady() {\n net.debug(`wait for ready ${this._busy.digitalRead()}`);\n if (this._busy.digitalRead()) {\n pauseUntil(() => !this._busy.digitalRead(), 10000);\n net.debug(`busy = ${this._busy.digitalRead()}`);\n // pause(1000)\n }\n if (this._busy.digitalRead()) {\n net.log(\"timed out waiting for ready\")\n return false\n }\n\n return true\n }\n\n private _sendCommand(cmd: number, params?: Buffer[], param_len_16?: boolean) {\n params = params || [];\n\n // compute buffer size\n let n = 3; // START_CMD, cmd, length\n params.forEach(param => {\n n += 1 + (param_len_16 ? 1 : 0) + param.length;\n })\n n += 1; // END_CMD\n // padding\n while (n % 4) n++;\n\n const packet = control.createBuffer(n);\n let k = 0;\n packet[k++] = _START_CMD;\n packet[k++] = cmd & ~_REPLY_FLAG;\n packet[k++] = params.length;\n\n params.forEach(param => {\n if (param_len_16)\n packet[k++] = (param.length >> 8) & 0xFF;\n packet[k++] = param.length & 0xFF;\n packet.write(k, param);\n k += param.length;\n })\n packet[k++] = _END_CMD;\n while (k < n)\n packet[k++] = 0xff;\n\n net.debug(`send cmd ${packet.toHex()}`)\n if (!this.waitForReady())\n return false\n this._cs.digitalWrite(false)\n this.spiTransfer(packet, null)\n this._cs.digitalWrite(true)\n net.debug(`send done`);\n return true\n }\n\n private spiTransfer(tx: Buffer, rx: Buffer) {\n if (!tx) tx = control.createBuffer(rx.length)\n if (!rx) rx = control.createBuffer(tx.length)\n this._spi.transfer(tx, rx);\n }\n\n private _waitResponseCmd(cmd: number, num_responses?: number, param_len_16?: boolean) {\n net.debug(`wait response cmd`);\n if (!this.waitForReady())\n return null\n\n this._cs.digitalWrite(false)\n\n let responses: Buffer[] = []\n if (!this.waitSPIChar(_START_CMD)) {\n this._cs.digitalWrite(true)\n return null\n }\n this.checkData(cmd | _REPLY_FLAG)\n if (num_responses !== undefined)\n this.checkData(num_responses, cmd + \"\")\n else\n num_responses = this.readByte();\n for (let num = 0; num < num_responses; ++num) {\n let param_len = this.readByte()\n if (param_len_16) {\n param_len <<= 8\n param_len |= this.readByte()\n }\n net.debug(`\\tParameter #${num} length is ${param_len}`)\n const response = control.createBuffer(param_len);\n this.spiTransfer(null, response)\n responses.push(response);\n }\n this.checkData(_END_CMD);\n\n this._cs.digitalWrite(true)\n\n net.debug(`responses ${responses.length}`);\n return responses;\n }\n\n private lock() {\n while (this._locked) {\n pauseUntil(() => !this._locked)\n }\n this._locked = true\n }\n\n private unlock() {\n if (!this._locked)\n net.fail(\"not locked!\")\n this._locked = false;\n }\n\n private sendCommandGetResponse(cmd: number, params?: Buffer[],\n reply_params = 1, sent_param_len_16 = false, recv_param_len_16 = false) {\n\n this.lock()\n this._sendCommand(cmd, params, sent_param_len_16)\n const resp = this._waitResponseCmd(cmd, reply_params, recv_param_len_16)\n this.unlock();\n return resp\n }\n\n get status(): number {\n const resp = this.sendCommandGetResponse(_GET_CONN_STATUS_CMD)\n if (!resp)\n return WL_NO_SHIELD\n net.debug(`status: ${resp[0][0]}`);\n // one byte response\n return resp[0][0];\n }\n\n /** A string of the firmware version on the ESP32 */\n get firmwareVersion(): string {\n let resp = this.sendCommandGetResponse(_GET_FW_VERSION_CMD)\n if (!resp)\n return \"not connected\"\n return resp[0].toString();\n }\n\n /** A bytearray containing the MAC address of the ESP32 */\n get MACaddress(): Buffer {\n let resp = this.sendCommandGetResponse(_GET_MACADDR_CMD, [hex`ff`])\n if (!resp)\n return null\n // for whatever reason, the mac adderss is backwards\n const res = control.createBuffer(6)\n for (let i = 0; i < 6; ++i)\n res[i] = resp[0][5 - i]\n return res\n }\n\n /** Begin a scan of visible access points. Follow up with a call\n to 'get_scan_networks' for response\n*/\n private startScanNetworks(): void {\n let resp = this.sendCommandGetResponse(_START_SCAN_NETWORKS)\n if (resp[0][0] != 1) {\n net.fail(\"failed to start AP scan\")\n }\n\n }\n\n /** The results of the latest SSID scan. Returns a list of dictionaries with\n 'ssid', 'rssi' and 'encryption' entries, one for each AP found\n*/\n private getScanNetworks(): net.AccessPoint[] {\n let names = this.sendCommandGetResponse(_SCAN_NETWORKS, undefined, undefined)\n // print(\"SSID names:\", names)\n // pylint: disable=invalid-name\n let APs = []\n let i = 0\n for (let name of names) {\n let a_p = new net.AccessPoint(name.toString())\n let rssi = this.sendCommandGetResponse(_GET_IDX_RSSI_CMD, [buffer1(i)])[0]\n a_p.rssi = pins.unpackBuffer(\"<i\", rssi)[0]\n let encr = this.sendCommandGetResponse(_GET_IDX_ENCT_CMD, [buffer1(1)])[0]\n if (encr[0])\n a_p.flags |= net.WifiAPFlags.HasPassword\n APs.push(a_p)\n i++\n }\n return APs\n }\n\n /** Scan for visible access points, returns a list of access point details.\n Returns a list of dictionaries with 'ssid', 'rssi' and 'encryption' entries,\n one for each AP found\n */\n protected scanNetworksCore(): net.AccessPoint[] {\n this.startScanNetworks()\n // attempts\n for (let _ = 0; _ < 10; ++_) {\n pause(2000)\n // pylint: disable=invalid-name\n let APs = this.getScanNetworks()\n if (APs) {\n for (const ap of APs)\n net.debug(` ${ap.ssid} => RSSI ${ap.rssi}`)\n return APs\n }\n\n }\n return null\n }\n\n /** Tells the ESP32 to set the access point to the given ssid */\n public wifiSetNetwork(ssid: string): void {\n const ssidbuf = control.createBufferFromUTF8(ssid);\n let resp = this.sendCommandGetResponse(_SET_NET_CMD, [ssidbuf])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set network\")\n }\n\n }\n\n /** Sets the desired access point ssid and passphrase */\n public wifiSetPassphrase(ssid: string, passphrase: string): void {\n const ssidbuf = control.createBufferFromUTF8(ssid);\n const passphrasebuf = control.createBufferFromUTF8(passphrase);\n let resp = this.sendCommandGetResponse(_SET_PASSPHRASE_CMD, [ssidbuf, passphrasebuf])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set passphrase\")\n }\n }\n\n /** Sets the WPA2 Enterprise anonymous identity */\n public wifiSetEntidentity(ident: string): void {\n const ssidbuf = control.createBufferFromUTF8(ident);\n let resp = this.sendCommandGetResponse(_SET_ENT_IDENT_CMD, [ssidbuf])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set enterprise anonymous identity\")\n }\n\n }\n\n /** Sets the desired WPA2 Enterprise username */\n public wifiSetEntusername(username: string): void {\n const usernamebuf = control.createBufferFromUTF8(username);\n let resp = this.sendCommandGetResponse(_SET_ENT_UNAME_CMD, [usernamebuf])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set enterprise username\")\n }\n\n }\n\n /** Sets the desired WPA2 Enterprise password */\n public wifiSetEntpassword(password: string): void {\n const passwordbuf = control.createBufferFromUTF8(password);\n let resp = this.sendCommandGetResponse(_SET_ENT_PASSWD_CMD, [passwordbuf])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set enterprise password\")\n }\n\n }\n\n /** Enables WPA2 Enterprise mode */\n public wifiSetEntenable(): void {\n let resp = this.sendCommandGetResponse(_SET_ENT_ENABLE_CMD)\n if (resp[0][0] != 1) {\n net.fail(\"failed to enable enterprise mode\")\n }\n\n }\n\n get ssidBuffer(): Buffer {\n let resp = this.sendCommandGetResponse(_GET_CURR_SSID_CMD, [hex`ff`])\n return resp[0]\n }\n\n get ssid(): string {\n const b = this.ssidBuffer;\n return b ? b.toString() : \"\";\n }\n\n get rssi(): number {\n let resp = this.sendCommandGetResponse(_GET_CURR_RSSI_CMD, [hex`ff`])\n return pins.unpackBuffer(\"<i\", resp[0])[0]\n }\n\n get networkData(): any {\n let resp = this.sendCommandGetResponse(_GET_IPADDR_CMD, [hex`ff`])\n return resp[0]; //?\n }\n\n get ipAddress(): string {\n return this.networkData[\"ip_addr\"]\n }\n\n get isConnected(): boolean {\n return this.status == WL_CONNECTED\n }\n\n get isIdle(): boolean {\n return this.status == WL_IDLE_STATUS;\n }\n\n /** \n * Connect to an access point with given name and password.\n * Will retry up to 10 times and return on success\n */\n connectAP(ssid: string, password: string): boolean {\n net.log(`connect to ${ssid}`)\n if (password) {\n this.wifiSetPassphrase(ssid, password)\n } else {\n this.wifiSetNetwork(ssid)\n }\n\n // retries\n let stat;\n for (let _ = 0; _ < 10; ++_) {\n stat = this.status\n if (stat == WL_CONNECTED) {\n this.wasConnected = true;\n net.log(\"connected\")\n return true;\n }\n pause(1000)\n }\n if ([WL_CONNECT_FAILED, WL_CONNECTION_LOST, WL_DISCONNECTED].indexOf(stat) >= 0) {\n net.log(`failed to connect to \"${ssid}\" (${stat})`)\n }\n\n if (stat == WL_NO_SSID_AVAIL) {\n net.log(`no such ssid: \"${ssid}\"`)\n }\n\n return false;\n }\n\n /** \n * Convert a hostname to a packed 4-byte IP address. Returns\n a 4 bytearray\n */\n public hostbyName(hostname: string): Buffer {\n if (!this.connect())\n return undefined;\n\n let resp = this.sendCommandGetResponse(_REQ_HOST_BY_NAME_CMD, [control.createBufferFromUTF8(hostname)])\n if (resp[0][0] != 1) {\n net.fail(\"failed to request hostname\")\n }\n\n resp = this.sendCommandGetResponse(_GET_HOST_BY_NAME_CMD)\n return resp[0];\n }\n\n /** Ping a destination IP address or hostname, with a max time-to-live\n (ttl). Returns a millisecond timing value\n */\n public ping(dest: string, ttl: number = 250): number {\n if (!this.connect())\n return -1;\n\n // convert to IP address\n let ip = this.hostbyName(dest)\n\n // ttl must be between 0 and 255\n ttl = Math.max(0, Math.min(ttl | 0, 255))\n let resp = this.sendCommandGetResponse(_PING_CMD, [ip, buffer1(ttl)])\n return pins.unpackBuffer(\"<H\", resp[0])[0];\n }\n\n /** Request a socket from the ESP32, will allocate and return a number that\n can then be passed to the other socket commands\n */\n public socket(): number {\n if (!this.connect())\n net.fail(\"can't connect\");\n\n net.debug(\"*** Get socket\")\n let resp0 = this.sendCommandGetResponse(_GET_SOCKET_CMD)\n let resp = resp0[0][0]\n if (resp == 255) {\n net.fail(\"no sockets available\")\n }\n net.debug(\"Allocated socket #\" + resp)\n return resp\n }\n\n /** Open a socket to a destination IP address or hostname\n using the ESP32's internal reference number. By default we use\n 'conn_mode' TCP_MODE but can also use UDP_MODE or TLS_MODE\n (dest must be hostname for TLS_MODE!)\n */\n public socketOpen(socket_num: number, dest: Buffer | string, port: number, conn_mode = net.TCP_MODE): void {\n this._socknum_ll[0][0] = socket_num\n net.debug(\"*** Open socket: \" + dest + \":\" + port)\n\n let port_param = pins.packBuffer(\">H\", [port])\n let resp: Buffer[]\n // use the 5 arg version\n if (typeof dest == \"string\") {\n const dest2 = control.createBufferFromUTF8(dest)\n resp = this.sendCommandGetResponse(_START_CLIENT_TCP_CMD, [dest2, hex`00000000`, port_param, this._socknum_ll[0], buffer1(conn_mode)])\n } else {\n // ip address, use 4 arg vesion\n resp = this.sendCommandGetResponse(_START_CLIENT_TCP_CMD, [dest, port_param, this._socknum_ll[0], buffer1(conn_mode)])\n }\n\n if (resp[0][0] != 1) {\n net.fail(\"could not connect to remote server\")\n }\n\n }\n\n /** Get the socket connection status, can be SOCKET_CLOSED, SOCKET_LISTEN,\n SOCKET_SYN_SENT, SOCKET_SYN_RCVD, SOCKET_ESTABLISHED, SOCKET_FIN_WAIT_1,\n SOCKET_FIN_WAIT_2, SOCKET_CLOSE_WAIT, SOCKET_CLOSING, SOCKET_LAST_ACK, or\n SOCKET_TIME_WAIT\n */\n public socketStatus(socket_num: number): number {\n this._socknum_ll[0][0] = socket_num\n let resp = this.sendCommandGetResponse(_GET_CLIENT_STATE_TCP_CMD, this._socknum_ll)\n return resp[0][0]\n }\n\n /** Test if a socket is connected to the destination, returns boolean true/false */\n public socket_connected(socket_num: number): boolean {\n return this.socketStatus(socket_num) == SOCKET_ESTABLISHED\n }\n\n /** Write the bytearray buffer to a socket */\n public socketWrite(socket_num: number, buffer: Buffer): void {\n net.debug(\"Writing:\" + buffer.length)\n this._socknum_ll[0][0] = socket_num\n let resp = this.sendCommandGetResponse(_SEND_DATA_TCP_CMD, [this._socknum_ll[0], buffer], 1, true)\n let sent = resp[0].getNumber(NumberFormat.UInt16LE, 0)\n if (sent != buffer.length) {\n net.fail(`failed to send ${buffer.length} bytes (sent ${sent})`)\n }\n\n resp = this.sendCommandGetResponse(_DATA_SENT_TCP_CMD, this._socknum_ll)\n if (resp[0][0] != 1) {\n net.fail(\"failed to verify data sent\")\n }\n\n }\n\n /** Determine how many bytes are waiting to be read on the socket */\n public socketAvailable(socket_num: number): number {\n this._socknum_ll[0][0] = socket_num\n let resp = this.sendCommandGetResponse(_AVAIL_DATA_TCP_CMD, this._socknum_ll)\n let reply = pins.unpackBuffer(\"<H\", resp[0])[0]\n net.debug(`ESPSocket: ${reply} bytes available`)\n return reply\n }\n\n /** Read up to 'size' bytes from the socket number. Returns a bytearray */\n public socketRead(socket_num: number, size: number): Buffer {\n net.debug(`Reading ${size} bytes from ESP socket with status ${this.socketStatus(socket_num)}`)\n this._socknum_ll[0][0] = socket_num\n let resp = this.sendCommandGetResponse(_GET_DATABUF_TCP_CMD,\n [this._socknum_ll[0], pins.packBuffer(\"<H\", [size])],\n 1, true, true)\n net.debug(`buf >>${resp[0].toString()}<<`)\n return resp[0]\n }\n\n /** Open and verify we connected a socket to a destination IP address or hostname\n using the ESP32's internal reference number. By default we use\n 'conn_mode' TCP_MODE but can also use UDP_MODE or TLS_MODE (dest must\n be hostname for TLS_MODE!)\n */\n public socketConnect(socket_num: number, dest: string | Buffer, port: number, conn_mode = net.TCP_MODE): boolean {\n net.debug(\"*** Socket connect mode \" + conn_mode)\n this.socketOpen(socket_num, dest, port, conn_mode)\n let times = net.monotonic()\n // wait 3 seconds\n while (net.monotonic() - times < 3) {\n if (this.socket_connected(socket_num)) {\n return true\n }\n\n pause(10)\n }\n net.fail(\"failed to establish connection\")\n return false\n }\n\n /** Close a socket using the ESP32's internal reference number */\n public socketClose(socket_num: number): void {\n net.debug(\"*** Closing socket #\" + socket_num)\n\n this._socknum_ll[0][0] = socket_num\n let resp = this.sendCommandGetResponse(_STOP_CLIENT_TCP_CMD, this._socknum_ll)\n if (resp[0][0] != 1) {\n net.fail(\"failed to close socket\")\n }\n\n }\n\n /** Enable/disable debug mode on the ESP32. Debug messages will be\n written to the ESP32's UART.\n */\n public setESPdebug(enabled: boolean) {\n let resp = this.sendCommandGetResponse(_SET_DEBUG_CMD, [buffer1(enabled ? 1 : 0)])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set debug mode\")\n }\n }\n\n public getTemperature() {\n let resp = this.sendCommandGetResponse(_GET_TEMP_CMD, [])\n if (resp[0].length != 4) {\n net.fail(\"failed to get temp\")\n }\n return resp[0].getNumber(NumberFormat.Float32LE, 0)\n }\n\n /** \n Set the io mode for a GPIO pin.\n \n :param int pin: ESP32 GPIO pin to set.\n :param value: direction for pin, digitalio.Direction or integer (0=input, 1=output).\n \n */\n public setPinMode(pin: number, pin_mode: number): void {\n\n let resp = this.sendCommandGetResponse(_SET_PIN_MODE_CMD, [buffer1(pin), buffer1(pin_mode)])\n if (resp[0][0] != 1) {\n net.fail(\"failed to set pin mode\")\n }\n\n }\n\n /** \n Set the digital output value of pin.\n \n :param int pin: ESP32 GPIO pin to write to.\n :param bool value: Value for the pin.\n \n */\n public setDigitalWrite(pin: number, value: number): void {\n let resp = this.sendCommandGetResponse(_SET_DIGITAL_WRITE_CMD, [buffer1(pin), buffer1(value)])\n if (resp[0][0] != 1) {\n net.fail(\"failed to write to pin\")\n }\n\n }\n\n /** \n Set the analog output value of pin, using PWM.\n \n :param int pin: ESP32 GPIO pin to write to.\n :param float value: 0=off 1.0=full on\n \n */\n public setAnalogWrite(pin: number, analog_value: number) {\n let value = Math.trunc(255 * analog_value)\n let resp = this.sendCommandGetResponse(_SET_ANALOG_WRITE_CMD, [buffer1(pin), buffer1(value)])\n if (resp[0][0] != 1) {\n net.fail(\"failed to write to pin\")\n }\n\n }\n }\n\n //% shim=esp32spi::flashDevice\n export function flashDevice() {\n return\n }\n}",
1662
- "pxt.json": "{\n \"name\": \"esp32\",\n \"description\": \"ESP32 over SPI - beta\",\n \"dependencies\": {\n \"core\": \"*\",\n \"net\": \"*\",\n \"settings\": \"*\"\n },\n \"files\": [\n \"net.ts\",\n \"ninacontroller.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1662
+ "pxt.json": "{\n \"name\": \"esp32\",\n \"description\": \"ESP32 over SPI - beta\",\n \"dependencies\": {\n \"core\": \"*\",\n \"net\": \"*\",\n \"settings\": \"*\"\n },\n \"files\": [\n \"net.ts\",\n \"ninacontroller.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1663
1663
  "test.ts": "function test() {\n\n const log = console.log;\n const esp = net.instance().controller()\n\n if (!esp.isIdle)\n return\n\n log(`Firmware vers. ${esp.firmwareVersion}`)\n log(`MAC addr: ${esp.MACaddress.toHex()}`)\n log(\"Temp: \" + esp.getTemperature())\n\n if (!esp.connect()) {\n log(\"can't connect\")\n return\n }\n\n log(\"ping: \" + esp.ping(\"bing.com\"))\n}\n\ntest();"
1664
1664
  },
1665
1665
  "feather": {
1666
1666
  "README.md": "# feather\n\nProvides pin definition for Adafruit Feather compatible boards.\n\n\nSee https://learn.adafruit.com/assets/78438",
1667
1667
  "device.d.ts": "declare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_A0)\n const A0: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_A1)\n const A1: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_A2)\n const A2: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_A3)\n const A3: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_A4)\n const A4: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_A5)\n const A5: PwmPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D0)\n const D0: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D1)\n const D1: PwmPin;\n\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D4)\n const D4: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D5)\n const D5: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D6)\n const D6: PwmPin;\n\n\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D9)\n const D9: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D10)\n const D10: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D11)\n const D11: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D12)\n const D12: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D13)\n const D13: PwmPin;\n\n}\n",
1668
- "pxt.json": "{\n \"name\": \"feather\",\n \"description\": \"Adafruit Feather pinout\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"device.d.ts\",\n \"targetoverrides.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"requiredCategories\": [\n \"pins\"\n ],\n \"weight\": 2,\n \"icon\": \"/static/libs/feather.png\"\n}\n",
1668
+ "pxt.json": "{\n \"name\": \"feather\",\n \"description\": \"Adafruit Feather pinout\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"device.d.ts\",\n \"targetoverrides.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"requiredCategories\": [\n \"pins\"\n ],\n \"weight\": 2,\n \"icon\": \"/static/libs/feather.png\"\n}\n",
1669
1669
  "targetoverrides.d.ts": "declare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D2)\n const D2: PwmPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_D3)\n const D3: PwmPin;\n}"
1670
1670
  },
1671
1671
  "game": {
@@ -1703,7 +1703,7 @@ var pxtTargetBundle = {
1703
1703
  "particles.ts": "namespace particles {\n enum Flag {\n enabled = 1 << 0,\n destroyed = 1 << 1,\n relativeToCamera = 1 << 2\n }\n\n // maximum count of sources before removing previous sources\n //% whenUsed\n const MAX_SOURCES = (() => {\n const sz = control.ramSize();\n if (sz <= 1024 * 100) {\n return 8;\n } else if (sz <= 1024 * 200) {\n return 16;\n } else {\n return 50;\n }\n })();\n const TIME_PRECISION = 10; // time goes down to down to the 1<<10 seconds\n let lastUpdate: number;\n\n /**\n * A single particle\n */\n //% maxBgInstances=200\n export class Particle {\n _x: Fx8;\n _y: Fx8;\n vx: Fx8;\n vy: Fx8;\n lifespan: number;\n next: Particle;\n data?: number;\n color?: number;\n }\n\n /**\n * An anchor for a Particle to originate from\n */\n export interface ParticleAnchor {\n x: number;\n y: number;\n vx?: number;\n vy?: number;\n width?: number;\n height?: number;\n image?: Image;\n flags?: number;\n setImage?: (i: Image) => void;\n }\n\n /**\n * A source of particles\n */\n export class ParticleSource extends sprites.BaseSprite {\n /**\n * A relative ranking of this sources priority\n * When necessary, a source with a lower priority will\n * be culled before a source with a higher priority.\n */\n priority: number;\n _dt: number;\n /**\n * The anchor this source is currently attached to\n */\n anchor: ParticleAnchor;\n /**\n * Time to live in milliseconds. The lifespan decreases by 1 on each millisecond\n * and the source gets destroyed when it reaches 0.\n */\n lifespan: number;\n\n protected pFlags: number;\n protected head: Particle;\n protected timer: number;\n protected period: number;\n protected _factory: ParticleFactory;\n\n protected ax: Fx8;\n protected ay: Fx8;\n\n /**\n * @param anchor to emit particles from\n * @param particlesPerSecond rate at which particles are emitted\n * @param factory [optional] factory to generate particles with; otherwise,\n */\n constructor(anchor: ParticleAnchor, particlesPerSecond: number, factory?: ParticleFactory) {\n super(scene.SPRITE_Z)\n init();\n const sources = particleSources();\n\n // remove and immediately destroy oldest source if over MAX_SOURCES\n if (sources.length >= MAX_SOURCES) {\n sortSources(sources);\n const removedSource = sources.shift();\n removedSource.clear();\n removedSource.destroy();\n }\n\n this.pFlags = 0;\n this.setRate(particlesPerSecond);\n this.setAcceleration(0, 0);\n this.setAnchor(anchor);\n this.lifespan = undefined;\n this._dt = 0;\n this.priority = 0;\n this.setFactory(factory || particles.defaultFactory);\n sources.push(this);\n this.enabled = true;\n }\n\n __draw(camera: scene.Camera) {\n let current = this.head;\n const left = (this.pFlags & Flag.relativeToCamera) ? Fx.zeroFx8 : Fx8(camera.drawOffsetX);\n const top = (this.pFlags & Flag.relativeToCamera) ? Fx.zeroFx8 : Fx8(camera.drawOffsetY);\n\n while (current) {\n if (current.lifespan > 0)\n this.drawParticle(current, left, top);\n current = current.next;\n }\n }\n\n _update(dt: number) {\n this.timer -= dt;\n\n if (this.lifespan !== undefined) {\n this.lifespan -= dt;\n if (this.lifespan <= 0) {\n this.lifespan = undefined;\n this.destroy();\n }\n } else if (this.anchor && this.anchor.flags !== undefined && (this.anchor.flags & sprites.Flag.Destroyed)) {\n this.lifespan = 750;\n }\n\n while (this.timer < 0 && this.enabled) {\n this.timer += this.period;\n const p = this._factory.createParticle(this.anchor);\n if (!p) continue; // some factories can decide to not produce a particle\n p.next = this.head;\n this.head = p;\n }\n\n if (!this.head) return;\n\n let current = this.head;\n\n this._dt += dt;\n let fixedDt = Fx8(this._dt);\n if (fixedDt) {\n do {\n if (current.lifespan > 0) {\n current.lifespan -= dt;\n this.updateParticle(current, fixedDt)\n }\n } while (current = current.next);\n this._dt = 0;\n } else {\n do {\n current.lifespan -= dt;\n } while (current = current.next);\n }\n }\n\n _prune() {\n while (this.head && this.head.lifespan <= 0) {\n this.head = this.head.next;\n }\n\n if ((this.pFlags & Flag.destroyed) && !this.head) {\n const scene = game.currentScene();\n if (scene)\n scene.allSprites.removeElement(this);\n const sources = particleSources();\n if (sources && sources.length)\n sources.removeElement(this);\n this.anchor == undefined;\n }\n\n let current = this.head;\n while (current && current.next) {\n if (current.next.lifespan <= 0) {\n current.next = current.next.next;\n } else {\n current = current.next;\n }\n }\n }\n\n /**\n * Sets the acceleration applied to the particles\n */\n setAcceleration(ax: number, ay: number) {\n this.ax = Fx8(ax);\n this.ay = Fx8(ay);\n }\n\n /**\n * Enables or disables particles\n * @param on\n */\n setEnabled(on: boolean) {\n this.enabled = on;\n }\n\n /**\n * Sets whether the particle source is drawn relative to the camera or not\n * @param on\n */\n setRelativeToCamera(on: boolean) {\n if (on) this.pFlags |= Flag.relativeToCamera\n else this.pFlags = ~(~this.pFlags | Flag.relativeToCamera);\n }\n\n get enabled() {\n return !!(this.pFlags & Flag.enabled);\n }\n\n /**\n * Set whether this source is currently enabled (emitting particles) or not\n */\n set enabled(v: boolean) {\n if (v !== this.enabled) {\n this.pFlags = v ? (this.pFlags | Flag.enabled) : (this.pFlags ^ Flag.enabled);\n this.timer = 0;\n }\n }\n\n /**\n * Destroy the source\n */\n destroy() {\n // The `_prune` step will finishing destroying this Source once all emitted particles finish rendering\n this.enabled = false;\n this.pFlags |= Flag.destroyed;\n this._prune();\n }\n\n /**\n * Clear all particles emitted from this source\n */\n clear() {\n this.head = undefined;\n }\n\n /**\n * Set a anchor for particles to be emitted from\n * @param anchor\n */\n setAnchor(anchor: ParticleAnchor) {\n this.anchor = anchor;\n }\n\n /**\n * Sets the number of particle created per second\n * @param particlesPerSecond\n */\n setRate(particlesPerSecond: number) {\n this.period = Math.ceil(1000 / particlesPerSecond);\n this.timer = 0;\n }\n\n get factory(): ParticleFactory {\n return this._factory;\n }\n\n /**\n * Sets the particle factory\n * @param factory\n */\n setFactory(factory: ParticleFactory) {\n if (factory)\n this._factory = factory;\n }\n\n protected updateParticle(p: Particle, fixedDt: Fx8) {\n fixedDt = Fx.rightShift(fixedDt, TIME_PRECISION);\n\n p.vx = Fx.add(p.vx, Fx.mul(this.ax, fixedDt));\n p.vy = Fx.add(p.vy, Fx.mul(this.ay, fixedDt));\n\n p._x = Fx.add(p._x, Fx.mul(p.vx, fixedDt));\n p._y = Fx.add(p._y, Fx.mul(p.vy, fixedDt));\n }\n\n protected drawParticle(p: Particle, screenLeft: Fx8, screenTop: Fx8) {\n this._factory.drawParticle(p, Fx.sub(p._x, screenLeft), Fx.sub(p._y, screenTop));\n }\n }\n\n //% whenUsed\n export const defaultFactory = new particles.SprayFactory(20, 0, 60);\n\n /**\n * Creates a new source of particles attached to a sprite\n * @param sprite\n * @param particlesPerSecond number of particles created per second\n */\n export function createParticleSource(sprite: Sprite, particlesPerSecond: number): ParticleSource {\n return new ParticleSource(sprite, particlesPerSecond);\n }\n\n function init() {\n const scene = game.currentScene();\n if (scene.particleSources) return;\n scene.particleSources = [];\n lastUpdate = control.millis();\n game.onUpdate(updateParticles);\n game.onUpdateInterval(250, pruneParticles);\n }\n\n function updateParticles() {\n const sources = particleSources();\n if (!sources) return;\n sortSources(sources);\n\n const time = control.millis();\n const dt = time - lastUpdate;\n lastUpdate = time;\n\n for (let i = 0; i < sources.length; i++) {\n sources[i]._update(dt);\n }\n }\n\n function pruneParticles() {\n const sources = particleSources();\n if (sources) sources.slice(0, sources.length).forEach(s => s._prune());\n }\n\n function sortSources(sources: ParticleSource[]) {\n sources.sort((a, b) => (a.priority - b.priority || a.id - b.id));\n }\n\n /**\n * A source of particles where particles will occasionally change speed based off of each other\n */\n export class FireSource extends ParticleSource {\n protected galois: Math.FastRandom;\n\n constructor(anchor: ParticleAnchor, particlesPerSecond: number, factory?: ParticleFactory) {\n super(anchor, particlesPerSecond, factory);\n this.galois = new Math.FastRandom();\n this.z = 20;\n }\n\n updateParticle(p: Particle, fixedDt: Fx8) {\n super.updateParticle(p, fixedDt);\n if (p.next && this.galois.percentChance(30)) {\n p.vx = p.next.vx;\n p.vy = p.next.vy;\n }\n }\n }\n\n /**\n * A source of particles where the particles oscillate horizontally, and occasionally change\n * between a given number of defined states\n */\n export class BubbleSource extends ParticleSource {\n protected maxState: number;\n protected galois: Math.FastRandom;\n stateChangePercentage: number;\n oscillationPercentage: number\n\n constructor(anchor: ParticleAnchor, particlesPerSecond: number, maxState: number, factory?: ParticleFactory) {\n super(anchor, particlesPerSecond, factory);\n this.galois = new Math.FastRandom();\n this.maxState = maxState;\n this.stateChangePercentage = 3;\n this.oscillationPercentage = 4;\n }\n\n updateParticle(p: Particle, fixedDt: Fx8) {\n super.updateParticle(p, fixedDt);\n if (this.galois.percentChance(this.stateChangePercentage)) {\n if (p.data < this.maxState) {\n p.data++;\n } else if (p.data > 0) {\n p.data--;\n }\n }\n\n if (this.galois.percentChance(this.oscillationPercentage)) {\n p.vx = Fx.neg(p.vx);\n }\n }\n }\n\n export function clearAll() {\n const sources = particleSources();\n if (sources) {\n sources.forEach(s => s.clear());\n pruneParticles();\n }\n }\n\n /**\n * Stop all particle sources from creating any new particles\n */\n export function disableAll() {\n const sources = particleSources();\n if (sources) {\n sources.forEach(s => s.enabled = false);\n pruneParticles();\n }\n }\n\n /**\n * Allow all particle sources to create any new particles\n */\n export function enableAll() {\n const sources = particleSources();\n if (sources) {\n sources.forEach(s => s.enabled = true);\n pruneParticles();\n }\n }\n\n function particleSources() {\n const sources = game.currentScene().particleSources;\n return sources;\n }\n}\n",
1704
1704
  "physics.ts": "class PhysicsEngine {\n constructor() {\n }\n\n /**\n * Adds sprite to the physics\n * @param sprite\n */\n addSprite(sprite: Sprite) { }\n\n removeSprite(sprite: Sprite) { }\n\n /** move a single sprite **/\n moveSprite(s: Sprite, dx: Fx8, dy: Fx8) { }\n\n draw() { }\n\n /** Apply physics and collisions to all sprites **/\n move(dt: number) { }\n\n setMaxSpeed(speed: number) { }\n\n overlaps(sprite: Sprite): Sprite[] { return []; }\n}\n\nconst MAX_TIME_STEP = 100; // milliseconds\nconst MIN_MOVE_GAP = Fx8(0.1);\n\nconst SPRITE_NO_TILE_OVERLAPS = SpriteFlag.GhostThroughTiles | sprites.Flag.Destroyed | SpriteFlag.RelativeToCamera;\nconst SPRITE_NO_WALL_COLLISION = SpriteFlag.GhostThroughWalls | sprites.Flag.IsClipping | sprites.Flag.Destroyed | SpriteFlag.RelativeToCamera;\nconst SPRITE_NO_SPRITE_OVERLAPS = SpriteFlag.GhostThroughSprites | sprites.Flag.Destroyed | SpriteFlag.RelativeToCamera;\n\nclass MovingSprite {\n constructor(\n public sprite: Sprite,\n // vx and vy when last updated\n public cachedVx: Fx8,\n public cachedVy: Fx8,\n // remaining x\n public dx: Fx8,\n public dy: Fx8,\n // how much to move per step\n public xStep: Fx8,\n public yStep: Fx8\n ) { }\n}\n\n/**\n * A physics engine that does simple AABB bounding box check\n */\nclass ArcadePhysicsEngine extends PhysicsEngine {\n protected sprites: Sprite[];\n protected map: sprites.SpriteMap;\n protected maxVelocity: Fx8;\n protected maxNegativeVelocity: Fx8;\n protected minSingleStep: Fx8;\n protected maxSingleStep: Fx8;\n\n constructor(maxVelocity = 500, minSingleStep = 2, maxSingleStep = 4) {\n super();\n this.sprites = [];\n this.map = new sprites.SpriteMap();\n this.maxSpeed = maxVelocity;\n this.maxStep = maxSingleStep;\n this.minStep = minSingleStep;\n }\n\n get maxSpeed(): number {\n return Fx.toInt(this.maxVelocity);\n }\n\n set maxSpeed(v: number) {\n this.maxVelocity = Fx8(v);\n this.maxNegativeVelocity = Fx.neg(this.maxVelocity);\n }\n\n get minStep(): number {\n return Fx.toInt(this.minSingleStep);\n }\n\n set minStep(v: number) {\n this.minSingleStep = Fx8(v);\n }\n\n get maxStep(): number {\n return Fx.toInt(this.maxSingleStep);\n }\n\n set maxStep(v: number) {\n this.maxSingleStep = Fx8(v);\n }\n\n setMaxSpeed(v: number) {\n this.maxSpeed = v;\n }\n\n addSprite(sprite: Sprite) {\n this.sprites.push(sprite);\n const tm = game.currentScene().tileMap;\n if (tm && tm.isOnWall(sprite)) {\n sprite.flags |= sprites.Flag.IsClipping;\n }\n }\n\n removeSprite(sprite: Sprite) {\n this.sprites.removeElement(sprite);\n }\n\n draw() {\n this.map.draw();\n }\n\n move(dt: number) {\n // Sprite movement logic is done in milliseconds to avoid rounding errors with Fx8 numbers\n const dtMs = Math.min(MAX_TIME_STEP, dt * 1000);\n const dt2 = Math.idiv(dtMs, 2);\n\n const scene = game.currentScene();\n\n const tileMap = scene.tileMap;\n const movingSprites = this.sprites\n .map(sprite => this.createMovingSprite(sprite, dtMs, dt2));\n\n // clear obstacles if moving on that axis\n this.sprites.forEach(s => {\n if (s.vx || s.vy) s.clearObstacles();\n });\n\n this.map.clear();\n this.map.resizeBuckets(this.sprites);\n\n const MAX_STEP_COUNT = Fx.toInt(\n Fx.idiv(\n Fx.imul(\n Fx.div(\n this.maxVelocity,\n this.minSingleStep\n ),\n dtMs\n ),\n 1000\n )\n );\n const overlapHandlers = scene.overlapHandlers.slice();\n\n // buffers store the moving sprites on each step; switch back and forth between the two\n let selected = 0;\n let buffers = [movingSprites, []];\n for (let count = 0; count < MAX_STEP_COUNT && buffers[selected].length !== 0; ++count) {\n const currMovers = buffers[selected];\n selected ^= 1;\n const remainingMovers = buffers[selected];\n\n for (let ms of currMovers) {\n const s = ms.sprite;\n // if still moving and speed has changed from a collision or overlap;\n // reverse direction if speed has reversed\n if (ms.cachedVx !== s._vx) {\n if (s._vx == Fx.zeroFx8) {\n ms.dx = Fx.zeroFx8;\n } else if (s._vx < Fx.zeroFx8 && ms.cachedVx > Fx.zeroFx8\n || s._vx > Fx.zeroFx8 && ms.cachedVx < Fx.zeroFx8) {\n ms.dx = Fx.neg(ms.dx);\n ms.xStep = Fx.neg(ms.xStep);\n }\n\n ms.cachedVx = s._vx;\n }\n if (ms.cachedVy !== s._vy) {\n if (s._vy == Fx.zeroFx8) {\n ms.dy = Fx.zeroFx8;\n } else if (s._vy < Fx.zeroFx8 && ms.cachedVy > Fx.zeroFx8\n || s._vy > Fx.zeroFx8 && ms.cachedVy < Fx.zeroFx8) {\n ms.dy = Fx.neg(ms.dy);\n ms.yStep = Fx.neg(ms.yStep);\n }\n\n ms.cachedVy = s._vy;\n }\n\n // identify how much to move in this step\n const stepX = Fx.abs(ms.xStep) > Fx.abs(ms.dx) ? ms.dx : ms.xStep;\n const stepY = Fx.abs(ms.yStep) > Fx.abs(ms.dy) ? ms.dy : ms.yStep;\n ms.dx = Fx.sub(ms.dx, stepX);\n ms.dy = Fx.sub(ms.dy, stepY);\n\n s._lastX = s._x;\n s._lastY = s._y;\n s._x = Fx.add(s._x, stepX);\n s._y = Fx.add(s._y, stepY);\n\n if (!(s.flags & SPRITE_NO_SPRITE_OVERLAPS)) {\n this.map.insertAABB(s);\n }\n if (tileMap && tileMap.enabled) {\n this.tilemapCollisions(ms, tileMap);\n }\n\n // check for screen edge collisions\n const bounce = s.flags & sprites.Flag.BounceOnWall;\n if (s.flags & sprites.Flag.StayInScreen || (bounce && !tileMap)) {\n this.screenEdgeCollisions(ms, bounce, scene.camera);\n }\n\n // if sprite still needs to move, add it to the next step of movements\n if (Fx.abs(ms.dx) > MIN_MOVE_GAP || Fx.abs(ms.dy) > MIN_MOVE_GAP) {\n remainingMovers.push(ms);\n }\n }\n\n // this step is done; check collisions between sprites\n this.spriteCollisions(currMovers, overlapHandlers);\n // clear moving sprites buffer for next step\n while (currMovers.length) currMovers.pop();\n }\n }\n\n protected createMovingSprite(sprite: Sprite, dtMs: number, dt2: number): MovingSprite {\n const ovx = this.constrain(sprite._vx);\n const ovy = this.constrain(sprite._vy);\n sprite._lastX = sprite._x;\n sprite._lastY = sprite._y;\n\n if (sprite._ax) {\n sprite._vx = Fx.add(\n sprite._vx,\n Fx.idiv(\n Fx.imul(\n sprite._ax,\n dtMs\n ),\n 1000\n )\n );\n } else if (sprite._fx) {\n const fx = Fx.idiv(\n Fx.imul(\n sprite._fx,\n dtMs\n ),\n 1000\n );\n const c = Fx.compare(sprite._vx, fx);\n if (c < 0) // v < f, v += f\n sprite._vx = Fx.min(Fx.zeroFx8, Fx.add(sprite._vx, fx));\n else if (c > 0) // v > f, v -= f\n sprite._vx = Fx.max(Fx.zeroFx8, Fx.sub(sprite._vx, fx));\n else\n sprite._vx = Fx.zeroFx8\n }\n\n if (sprite._ay) {\n sprite._vy = Fx.add(\n sprite._vy,\n Fx.idiv(\n Fx.imul(\n sprite._ay,\n dtMs\n ),\n 1000\n )\n );\n } else if (sprite._fy) {\n const fy = Fx.idiv(\n Fx.imul(\n sprite._fy,\n dtMs\n ),\n 1000\n );\n const c = Fx.compare(sprite._vy, fy);\n if (c < 0) // v < f, v += f\n sprite._vy = Fx.min(Fx.zeroFx8, Fx.add(sprite._vy, fy));\n else if (c > 0) // v > f, v -= f\n sprite._vy = Fx.max(Fx.zeroFx8, Fx.sub(sprite._vy, fy));\n else\n sprite._vy = Fx.zeroFx8;\n }\n\n sprite._vx = this.constrain(sprite._vx);\n sprite._vy = this.constrain(sprite._vy);\n\n const dx = Fx8(Fx.toFloat(Fx.add(sprite._vx, ovx)) * dt2 / 1000);\n const dy = Fx8(Fx.toFloat(Fx.add(sprite._vy, ovy)) * dt2 / 1000);\n\n let xStep = dx;\n let yStep = dy;\n\n // make step increments smaller until under max step size\n while (Fx.abs(xStep) > this.maxSingleStep || Fx.abs(yStep) > this.maxSingleStep) {\n if (Fx.abs(xStep) > this.minSingleStep) {\n xStep = Fx.idiv(xStep, 2);\n }\n if (Fx.abs(yStep) > this.minSingleStep) {\n yStep = Fx.idiv(yStep, 2);\n }\n }\n\n return new MovingSprite(\n sprite,\n sprite._vx,\n sprite._vy,\n dx,\n dy,\n xStep,\n yStep\n );\n }\n\n protected spriteCollisions(movedSprites: MovingSprite[], handlers: scene.OverlapHandler[]) {\n control.enablePerfCounter(\"phys_collisions\");\n if (!handlers.length) return;\n\n // sprites that have moved this step\n for (const ms of movedSprites) {\n const sprite = ms.sprite;\n if (sprite.flags & SPRITE_NO_SPRITE_OVERLAPS) continue;\n const overSprites = this.map.overlaps(ms.sprite);\n\n for (const overlapper of overSprites) {\n if (overlapper.flags & SPRITE_NO_SPRITE_OVERLAPS) continue;\n const thisKind = sprite.kind();\n const otherKind = overlapper.kind();\n\n // skip if no overlap event between these two kinds of sprites\n if (sprite._kindsOverlappedWith.indexOf(otherKind) === -1) continue;\n\n // Maintaining invariant that the sprite with the higher ID has the other sprite as an overlapper\n const higher = sprite.id > overlapper.id ? sprite : overlapper;\n const lower = higher === sprite ? overlapper : sprite;\n\n // if the two sprites are not currently engaged in an overlap event,\n // apply all matching overlap events\n if (higher._overlappers.indexOf(lower.id) === -1) {\n handlers\n .filter(h => (h.kind === thisKind && h.otherKind === otherKind)\n || (h.kind === otherKind && h.otherKind === thisKind)\n )\n .forEach(h => {\n higher._overlappers.push(lower.id);\n control.runInParallel(() => {\n if (!((sprite.flags | overlapper.flags) & SPRITE_NO_SPRITE_OVERLAPS)) {\n h.handler(\n thisKind === h.kind ? sprite : overlapper,\n thisKind === h.kind ? overlapper : sprite\n );\n }\n higher._overlappers.removeElement(lower.id);\n });\n });\n }\n }\n }\n }\n\n protected screenEdgeCollisions(movingSprite: MovingSprite, bounce: number, camera: scene.Camera) {\n let s = movingSprite.sprite;\n if (!s.isStatic()) s.setHitbox();\n if (!camera.isUpdated()) camera.update();\n\n let offset = Fx.toFloat(s._hitbox.left) - camera.offsetX;\n if (offset < 0) {\n s.left -= offset;\n if (bounce) s.vx = -s.vx;\n }\n else if ((offset = Fx.toFloat(s._hitbox.right) - camera.offsetX - screen.width) > 0) {\n s.right -= offset;\n if (bounce) s.vx = -s.vx;\n }\n if ((offset = Fx.toFloat(s._hitbox.top) - camera.offsetY) < 0) {\n s.top -= offset;\n if (bounce) s.vy = -s.vy;\n }\n else if ((offset = Fx.toFloat(s._hitbox.bottom) - camera.offsetY - screen.height) > 0) {\n s.bottom -= offset;\n if (bounce) s.vy = -s.vy;\n }\n }\n\n protected tilemapCollisions(movingSprite: MovingSprite, tm: tiles.TileMap) {\n const s = movingSprite.sprite;\n // if the sprite is already clipping into a wall,\n // allow free movement rather than randomly 'fixing' it\n if (s.flags & sprites.Flag.IsClipping) {\n if (!tm.isOnWall(s)) {\n s.flags &= ~sprites.Flag.IsClipping;\n }\n }\n if (!s.isStatic()) s.setHitbox();\n const hbox = s._hitbox;\n const tileScale = tm.scale;\n const tileSize = 1 << tileScale;\n\n const xDiff = Fx.sub(\n s._x,\n s._lastX\n );\n\n const yDiff = Fx.sub(\n s._y,\n s._lastY\n );\n\n if (!(s.flags & SPRITE_NO_WALL_COLLISION)) {\n if (xDiff !== Fx.zeroFx8) {\n const right = xDiff > Fx.zeroFx8;\n const x0 = Fx.toIntShifted(\n Fx.add(\n right ?\n Fx.add(hbox.right, Fx.oneFx8)\n :\n Fx.sub(hbox.left, Fx.oneFx8),\n Fx.oneHalfFx8\n ),\n tileScale\n );\n\n const collidedTiles: sprites.StaticObstacle[] = [];\n\n // check collisions with tiles sprite is moving towards horizontally\n for (\n let y = Fx.sub(hbox.top, yDiff);\n y < Fx.iadd(tileSize, Fx.sub(hbox.bottom, yDiff));\n y = Fx.iadd(tileSize, y)\n ) {\n const y0 = Fx.toIntShifted(\n Fx.add(\n Fx.min(\n y,\n Fx.sub(\n hbox.bottom,\n yDiff\n )\n ),\n Fx.oneHalfFx8\n ),\n tileScale\n );\n\n if (tm.isObstacle(x0, y0)) {\n const obstacle = tm.getObstacle(x0, y0);\n if (!collidedTiles.some(o => o.tileIndex === obstacle.tileIndex)) {\n collidedTiles.push(obstacle);\n }\n }\n }\n\n if (collidedTiles.length) {\n const collisionDirection = right ? CollisionDirection.Right : CollisionDirection.Left;\n s._x = Fx.sub(\n right ?\n Fx.sub(\n Fx8(x0 << tileScale),\n hbox.width\n )\n :\n Fx8((x0 + 1) << tileScale),\n hbox.ox\n );\n\n for (const tile of collidedTiles) {\n if(!(s.flags & SPRITE_NO_WALL_COLLISION)) {\n s.registerObstacle(collisionDirection, tile, tm);\n }\n }\n\n if (s.flags & sprites.Flag.DestroyOnWall) {\n s.destroy();\n } else if (s._vx === movingSprite.cachedVx && !(s.flags & SPRITE_NO_WALL_COLLISION)) {\n // sprite collision event didn't change velocity in this direction;\n // apply normal updates\n if (s.flags & sprites.Flag.BounceOnWall) {\n if ((!right && s.vx < 0) || (right && s.vx > 0)) {\n s._vx = Fx.neg(s._vx);\n movingSprite.xStep = Fx.neg(movingSprite.xStep);\n movingSprite.dx = Fx.neg(movingSprite.dx);\n }\n } else {\n movingSprite.dx = Fx.zeroFx8;\n s._vx = Fx.zeroFx8;\n }\n } else if (Math.sign(Fx.toInt(s._vx)) === Math.sign(Fx.toInt(movingSprite.cachedVx))) {\n // sprite collision event changed velocity,\n // but still facing same direction; prevent further movement this update.\n movingSprite.dx = Fx.zeroFx8;\n }\n }\n }\n\n if (yDiff !== Fx.zeroFx8) {\n const down = yDiff > Fx.zeroFx8;\n const y0 = Fx.toIntShifted(\n Fx.add(\n down ?\n Fx.add(hbox.bottom, Fx.oneFx8)\n :\n Fx.sub(hbox.top, Fx.oneFx8),\n Fx.oneHalfFx8\n ),\n tileScale\n );\n const collidedTiles: sprites.StaticObstacle[] = [];\n\n // check collisions with tiles sprite is moving towards vertically\n for (\n let x = hbox.left;\n x < Fx.iadd(tileSize, hbox.right);\n x = Fx.iadd(tileSize, x)\n ) {\n const x0 = Fx.toIntShifted(\n Fx.add(\n Fx.min(\n x,\n hbox.right\n ),\n Fx.oneHalfFx8\n ),\n tileScale\n );\n\n if (tm.isObstacle(x0, y0)) {\n const obstacle = tm.getObstacle(x0, y0);\n if (!collidedTiles.some(o => o.tileIndex === obstacle.tileIndex)) {\n collidedTiles.push(obstacle);\n }\n }\n }\n\n if (collidedTiles.length) {\n const collisionDirection = down ? CollisionDirection.Bottom : CollisionDirection.Top;\n s._y = Fx.sub(\n down ?\n Fx.sub(\n Fx8(y0 << tileScale),\n hbox.height\n )\n :\n Fx8((y0 + 1) << tileScale),\n hbox.oy\n );\n\n for (const tile of collidedTiles) {\n if(!(s.flags & SPRITE_NO_WALL_COLLISION)) {\n s.registerObstacle(collisionDirection, tile, tm);\n }\n }\n\n if (s.flags & sprites.Flag.DestroyOnWall) {\n s.destroy();\n } else if (s._vy === movingSprite.cachedVy && !(s.flags & SPRITE_NO_WALL_COLLISION)) {\n // sprite collision event didn't change velocity in this direction;\n // apply normal updates\n if (s.flags & sprites.Flag.BounceOnWall) {\n if ((!down && s.vy < 0) || (down && s.vy > 0)) {\n s._vy = Fx.neg(s._vy);\n movingSprite.yStep = Fx.neg(movingSprite.yStep);\n movingSprite.dy = Fx.neg(movingSprite.dy);\n }\n } else {\n movingSprite.dy = Fx.zeroFx8;\n s._vy = Fx.zeroFx8;\n }\n } else if (Math.sign(Fx.toInt(s._vy)) === Math.sign(Fx.toInt(movingSprite.cachedVy))) {\n // sprite collision event changed velocity,\n // but still facing same direction; prevent further movement this update.\n movingSprite.dy = Fx.zeroFx8;\n }\n }\n }\n }\n\n\n if (!(s.flags & SPRITE_NO_TILE_OVERLAPS)) {\n // Now that we've moved, check all of the tiles underneath the current position\n // for overlaps\n const overlappedTiles: tiles.Location[] = [];\n for (\n let x = hbox.left;\n x < Fx.iadd(tileSize, hbox.right);\n x = Fx.iadd(tileSize, x)\n ) {\n const x0 = Fx.toIntShifted(\n Fx.add(\n Fx.min(\n x,\n hbox.right\n ),\n Fx.oneHalfFx8\n ),\n tileScale\n );\n for (\n let y = hbox.top;\n y < Fx.iadd(tileSize, hbox.bottom);\n y = Fx.iadd(tileSize, y)\n ) {\n const y0 = Fx.toIntShifted(\n Fx.add(\n Fx.min(\n y,\n hbox.bottom\n ),\n Fx.oneHalfFx8\n ),\n tileScale\n );\n\n // if the sprite can move through walls, it can overlap the underlying tile.\n if (!tm.isObstacle(x0, y0) || !!(s.flags & sprites.Flag.GhostThroughWalls)) {\n overlappedTiles.push(tm.getTile(x0, y0));\n }\n }\n }\n\n if (overlappedTiles.length) {\n this.tilemapOverlaps(s, overlappedTiles);\n }\n }\n }\n\n /**\n * Given a sprite and a list of overlapped tiles, checks the overlap handlers and calls\n * the ones appropriate to the sprite and tile kind.\n * @param sprite the sprite\n * @param overlappedTiles the list of tiles the sprite is overlapping\n */\n protected tilemapOverlaps(sprite: Sprite, overlappedTiles: tiles.Location[]) {\n const alreadyHandled: tiles.Location[] = [];\n\n for (const tile of overlappedTiles) {\n if (alreadyHandled.some(l => l.column === tile.column && l.row === tile.row)) {\n continue;\n }\n alreadyHandled.push(tile);\n\n const tileOverlapHandlers = game.currentScene().tileOverlapHandlers;\n if (tileOverlapHandlers) {\n tileOverlapHandlers\n .filter(h => h.spriteKind == sprite.kind() && h.tileKind.equals(tiles.getTileImage(tile)))\n .forEach(h => h.handler(sprite, tile));\n }\n }\n }\n\n /**\n * Returns sprites that overlap with the given sprite. If type is non-zero, also filter by type.\n * @param sprite\n * @param layer\n */\n overlaps(sprite: Sprite): Sprite[] {\n return this.map.overlaps(sprite);\n }\n\n /** moves a sprite explicitly outside of the normal velocity changes **/\n public moveSprite(s: Sprite, dx: Fx8, dy: Fx8) {\n s._lastX = s._x;\n s._lastY = s._y;\n s._x = Fx.add(s._x, dx);\n s._y = Fx.add(s._y, dy);\n\n // if the sprite can collide with things, check tile map\n const tm = game.currentScene().tileMap;\n if (tm && tm.enabled) {\n const maxDist = Fx.toInt(this.maxSingleStep);\n // only check tile map if moving within a single step\n if (Math.abs(Fx.toInt(dx)) <= maxDist && Math.abs(Fx.toInt(dy)) <= maxDist) {\n const ms = new MovingSprite(\n s,\n s._vx,\n s._vy,\n dx,\n dy,\n dx,\n dy\n );\n this.tilemapCollisions(ms, tm);\n // otherwise, accept movement...\n } else if (tm.isOnWall(s) && !this.canResolveClipping(s, tm)) {\n // if no luck, flag as clipping into a wall\n s.flags |= sprites.Flag.IsClipping;\n } else {\n // or clear clipping if no longer clipping\n s.flags &= ~sprites.Flag.IsClipping;\n }\n }\n }\n\n // Attempt to resolve clipping by moving the sprite slightly up / down / left / right\n protected canResolveClipping(s: Sprite, tm: tiles.TileMap) {\n if (!s.isStatic()) s.setHitbox();\n const hbox = s._hitbox;\n const sz = 1 << tm.scale;\n const maxMove = this.maxStep;\n const origY = s._y;\n const origX = s._x;\n const l = Fx.toInt(hbox.left);\n const r = Fx.toInt(hbox.right);\n const t = Fx.toInt(hbox.top);\n const b = Fx.toInt(hbox.bottom);\n\n { // bump up and test;\n const offset = (b + 1) % sz;\n if (offset <= maxMove) {\n s._y = Fx.sub(\n s._y,\n Fx8(offset)\n );\n if (!tm.isOnWall(s)) {\n return true;\n } else {\n s._y = origY;\n }\n }\n }\n { // bump down and test;\n const offset = (Math.floor(t / sz) + 1) * sz - t;\n if (offset <= maxMove) {\n s._y = Fx.add(\n s._y,\n Fx8(offset)\n );\n if (!tm.isOnWall(s)) {\n return true;\n } else {\n s._y = origY;\n }\n }\n }\n { // bump left and test;\n const offset = (r + 1) % sz;\n if (offset <= maxMove) {\n s._x = Fx.sub(\n s._x,\n Fx8(offset)\n );\n if (!tm.isOnWall(s)) {\n return true;\n } else {\n s._x = origX;\n }\n }\n }\n { // bump right and test;\n const offset = (Math.floor(l / sz) + 1) * sz - l;\n if (offset <= maxMove) {\n s._x = Fx.add(\n s._x,\n Fx8(offset)\n );\n if (!tm.isOnWall(s)) {\n return true;\n } else {\n s._x = origX;\n }\n }\n }\n\n // no trivial adjustment worked; it's going to clip for now\n return false;\n }\n\n protected constrain(v: Fx8) {\n return Fx.max(\n Fx.min(\n this.maxVelocity,\n v\n ),\n this.maxNegativeVelocity\n );\n }\n}\n",
1705
1705
  "prompt.ts": "namespace game {\n export interface PromptTheme {\n colorPrompt: number;\n colorInput: number;\n colorInputHighlighted: number;\n colorInputText: number;\n colorAlphabet: number;\n colorCursor: number;\n colorBackground: number;\n colorBottomBackground: number;\n colorBottomText: number;\n }\n\n /**\n * Ask the player for a string value.\n * @param message The message to display on the text-entry screen\n * @param answerLength The maximum number of characters the user can enter (1 - 24)\n */\n //% weight=10 help=game/ask-for-string\n //% blockId=gameaskforstring block=\"ask for string %message || and max length %answerLength\"\n //% message.shadow=text\n //% message.defl=\"\"\n //% answerLength.defl=\"12\"\n //% answerLength.min=1\n //% answerLength.max=24\n //% group=\"Prompt\"\n export function askForString(message: any, answerLength = 12) {\n let p = new game.Prompt();\n const result = p.show(console.inspect(message), answerLength);\n return result;\n }\n\n\n //% whenUsed=true\n const font = image.font8; // FONT8-TODO\n //% whenUsed=true\n const PADDING = 4;\n //% whenUsed=true\n const PROMPT_LINE_SPACING = 2;\n\n //% whenUsed=true\n const NUM_LETTERS = 26;\n //% whenUsed=true\n const ALPHABET_ROW_LENGTH = 12;\n //% whenUsed=true\n const NUM_ROWS = Math.ceil(NUM_LETTERS / ALPHABET_ROW_LENGTH);\n //% whenUsed=true\n const INPUT_ROWS = 2;\n\n //% whenUsed=true\n const CONTENT_WIDTH = screen.width - PADDING * 2;\n //% whenUsed=true\n const CONTENT_HEIGHT = screen.height - PADDING * 2;\n //% whenUsed=true\n const CONTENT_TOP = PADDING;\n\n // Dimensions of a \"cell\" that contains a letter\n //% whenUsed=true\n const CELL_WIDTH = Math.floor(CONTENT_WIDTH / ALPHABET_ROW_LENGTH);\n //% whenUsed=true\n const CELL_HEIGHT = CELL_WIDTH;\n //% whenUsed=true\n const LETTER_OFFSET_X = Math.floor((CELL_WIDTH - font.charWidth) / 2);\n //% whenUsed=true\n const LETTER_OFFSET_Y = Math.floor((CELL_HEIGHT - font.charHeight) / 2);\n //% whenUsed=true\n const BLANK_PADDING = 1;\n //% whenUsed=true\n const ROW_LEFT = PADDING + CELL_WIDTH / 2 + Math.floor((CONTENT_WIDTH - (CELL_WIDTH * ALPHABET_ROW_LENGTH)) / 2);\n\n // Dimensions of the bottom bar\n //% whenUsed=true\n const BOTTOM_BAR_ALPHABET_MARGIN = 4;\n //% whenUsed=true\n const BOTTOM_BAR_HEIGHT = PADDING + BOTTOM_BAR_ALPHABET_MARGIN + CELL_HEIGHT;\n //% whenUsed=true\n const BOTTOM_BAR_TOP = screen.height - BOTTOM_BAR_HEIGHT;\n //% whenUsed=true\n const BOTTOM_BAR_BUTTON_WIDTH = PADDING * 2 + font.charWidth * 3;\n //% whenUsed=true\n const BOTTOM_BAR_TEXT_Y = (BOTTOM_BAR_HEIGHT - font.charHeight) / 2;\n //% whenUsed=true\n const BOTTOM_BAR_SHIFT_X = (BOTTOM_BAR_BUTTON_WIDTH - font.charWidth * 3) / 2;\n //% whenUsed=true\n const BOTTOM_BAR_CONFIRM_X = (BOTTOM_BAR_BUTTON_WIDTH - font.charWidth * 2) / 2;\n //% whenUsed=true\n const CONFIRM_BUTTON_LEFT = screen.width - BOTTOM_BAR_BUTTON_WIDTH;\n\n // Dimensions of the alphabet area\n //% whenUsed=true\n const ALPHABET_HEIGHT = NUM_ROWS * CELL_HEIGHT;\n //% whenUsed=true\n const ALPHABET_TOP = CONTENT_TOP + CONTENT_HEIGHT - ALPHABET_HEIGHT - BOTTOM_BAR_HEIGHT;\n //% whenUsed=true\n const ALPHABET_INPUT_MARGIN = 10;\n\n // Dimensions of area where text is input\n //% whenUsed=true\n const INPUT_HEIGHT = INPUT_ROWS * CELL_HEIGHT;\n //% whenUsed=true\n const INPUT_TOP = ALPHABET_TOP - INPUT_HEIGHT - ALPHABET_INPUT_MARGIN;\n\n // Dimensions of prompt message area\n //% whenUsed=true\n const PROMPT_HEIGHT = INPUT_TOP - CONTENT_TOP;\n\n //% whenUsed=true\n const lowerShiftText = \"ABC\";\n //% whenUsed=true\n const upperShiftText = \"abc\";\n //% whenUsed=true\n const digitsUpper = [\" \", \",\", \".\", \"?\", \"!\", \":\", \";\", \"\\\"\", \"(\", \")\"];\n //% whenUsed=true\n const confirmText = \"OK\";\n\n\n export class Prompt {\n theme: PromptTheme;\n\n message: string;\n answerLength: number;\n result: string;\n\n private cursor: Sprite;\n private shiftButton: Sprite;\n private confirmButton: Sprite;\n\n private letters: Sprite[];\n private inputs: Sprite[];\n\n private confirmPressed: boolean;\n private cursorRow: number;\n private cursorColumn: number;\n private upper: boolean;\n private inputIndex: number;\n private blink: boolean;\n private frameCount: number;\n\n constructor(theme?: PromptTheme) {\n if (theme) {\n this.theme = theme;\n }\n else {\n this.theme = {\n colorPrompt: 1,\n colorInput: 3,\n colorInputHighlighted: 5,\n colorInputText: 1,\n colorAlphabet: 1,\n colorCursor: 7,\n colorBackground: 15,\n colorBottomBackground: 3,\n colorBottomText: 1,\n };\n }\n this.cursorRow = 0;\n this.cursorColumn = 0;\n this.upper = false;\n this.inputIndex = 0;\n }\n\n show(message: string, answerLength: number) {\n this.message = message;\n this.answerLength = answerLength;\n this.inputIndex = 0;\n\n controller._setUserEventsEnabled(false);\n game.pushScene()\n\n this.draw();\n this.registerHandlers();\n this.confirmPressed = false;\n\n pauseUntil(() => this.confirmPressed);\n\n game.popScene();\n controller._setUserEventsEnabled(true);\n\n return this.result;\n }\n\n private draw() {\n this.drawPromptText();\n this.drawKeyboard();\n this.drawInputarea();\n this.drawBottomBar();\n }\n\n private drawPromptText() {\n const prompt = sprites.create(layoutText(this.message, CONTENT_WIDTH, PROMPT_HEIGHT, this.theme.colorPrompt), -1);\n prompt.x = screen.width / 2\n prompt.y = CONTENT_TOP + Math.floor((PROMPT_HEIGHT - prompt.height) / 2) + Math.floor(prompt.height / 2);\n }\n\n private drawInputarea() {\n const answerLeft = ROW_LEFT + Math.floor(\n ((CELL_WIDTH * ALPHABET_ROW_LENGTH) -\n CELL_WIDTH * Math.min(this.answerLength, ALPHABET_ROW_LENGTH)) / 2);\n\n this.inputs = [];\n for (let i = 0; i < this.answerLength; i++) {\n const blank = image.create(CELL_WIDTH, CELL_HEIGHT);\n this.drawInput(blank, \"\", this.theme.colorInput);\n\n const col = i % ALPHABET_ROW_LENGTH;\n const row = Math.floor(i / ALPHABET_ROW_LENGTH);\n\n const s = sprites.create(blank, -1);\n s.x = answerLeft + col * CELL_WIDTH;\n s.y = INPUT_TOP + row * CELL_HEIGHT;\n this.inputs.push(s);\n }\n }\n\n private drawKeyboard() {\n const cursorImage = image.create(CELL_WIDTH, CELL_HEIGHT);\n cursorImage.fill(this.theme.colorCursor);\n this.cursor = sprites.create(cursorImage, -1);\n this.cursor.z = -1;\n this.updateCursor();\n\n this.letters = [];\n for (let j = 0; j < 36; j++) {\n const letter = image.create(CELL_WIDTH, CELL_HEIGHT);\n\n const col2 = j % ALPHABET_ROW_LENGTH;\n const row2 = Math.floor(j / ALPHABET_ROW_LENGTH);\n\n const t = sprites.create(letter, -1);\n t.x = ROW_LEFT + col2 * CELL_WIDTH;\n t.y = ALPHABET_TOP + row2 * CELL_HEIGHT;\n\n this.letters.push(t);\n }\n this.updateKeyboard();\n }\n\n private drawBottomBar() {\n const bg = image.create(screen.width, BOTTOM_BAR_HEIGHT);\n bg.fill(this.theme.colorBottomBackground);\n\n const bgSprite = sprites.create(bg, -1);\n bgSprite.x = screen.width / 2;\n bgSprite.y = BOTTOM_BAR_TOP + BOTTOM_BAR_HEIGHT / 2;\n bgSprite.z = -1;\n\n this.shiftButton = sprites.create(image.create(BOTTOM_BAR_BUTTON_WIDTH, BOTTOM_BAR_HEIGHT), -1);\n this.shiftButton.x = Math.floor(BOTTOM_BAR_BUTTON_WIDTH / 2);\n this.shiftButton.y = BOTTOM_BAR_TOP + Math.ceil(BOTTOM_BAR_HEIGHT / 2);\n\n this.confirmButton = sprites.create(image.create(BOTTOM_BAR_BUTTON_WIDTH, BOTTOM_BAR_HEIGHT), -1);\n this.confirmButton.x = CONFIRM_BUTTON_LEFT + Math.floor(BOTTOM_BAR_BUTTON_WIDTH / 2);\n this.confirmButton.y = BOTTOM_BAR_TOP + Math.ceil(BOTTOM_BAR_HEIGHT / 2);\n\n this.updateButtons();\n }\n\n private updateButtons() {\n if (this.cursorRow === 3 && this.cursorColumn % 2 !== 1) {\n this.shiftButton.image.fill(this.theme.colorCursor);\n }\n else {\n this.shiftButton.image.fill(this.theme.colorBottomBackground);\n }\n\n if (this.upper) {\n this.shiftButton.image.print(upperShiftText, BOTTOM_BAR_SHIFT_X, BOTTOM_BAR_TEXT_Y);\n }\n else {\n this.shiftButton.image.print(lowerShiftText, BOTTOM_BAR_SHIFT_X, BOTTOM_BAR_TEXT_Y);\n }\n\n\n if (this.cursorRow === 3 && this.cursorColumn % 2) {\n this.confirmButton.image.fill(this.theme.colorCursor);\n }\n else {\n this.confirmButton.image.fill(this.theme.colorBottomBackground);\n }\n\n this.confirmButton.image.print(confirmText, BOTTOM_BAR_CONFIRM_X, BOTTOM_BAR_TEXT_Y);\n }\n\n private updateCursor() {\n if (this.cursorRow === 3) {\n this.cursor.image.fill(0);\n this.updateButtons();\n }\n else {\n this.cursor.x = ROW_LEFT + this.cursorColumn * CELL_WIDTH;\n this.cursor.y = ALPHABET_TOP + this.cursorRow * CELL_HEIGHT;\n }\n }\n\n private updateSelectedInput() {\n if (this.inputIndex < this.answerLength) {\n const u = this.inputs[this.inputIndex];\n if (this.blink) {\n this.drawInput(u.image, \"\", this.theme.colorInput);\n }\n else {\n this.drawInput(u.image, \"\", this.theme.colorInputHighlighted)\n }\n }\n }\n\n private updateKeyboard() {\n const len = this.letters.length;\n for (let k = 0; k < len; k++) {\n const img = this.letters[k].image;\n img.fill(0);\n img.print(getCharForIndex(k, this.upper), LETTER_OFFSET_X, LETTER_OFFSET_Y);\n }\n }\n\n private drawInput(img: Image, char: string, color: number) {\n img.fill(0);\n img.fillRect(BLANK_PADDING, CELL_HEIGHT - 1, CELL_WIDTH - BLANK_PADDING * 2, 1, color)\n\n if (char) {\n img.print(char, LETTER_OFFSET_X, LETTER_OFFSET_Y, this.theme.colorInputText, font);\n }\n }\n\n private registerHandlers() {\n controller.up.onEvent(SYSTEM_KEY_DOWN, () => {\n this.moveVertical(true);\n })\n\n controller.down.onEvent(SYSTEM_KEY_DOWN, () => {\n this.moveVertical(false);\n })\n\n controller.right.onEvent(SYSTEM_KEY_DOWN, () => {\n this.moveHorizontal(true);\n });\n\n controller.left.onEvent(SYSTEM_KEY_DOWN, () => {\n this.moveHorizontal(false);\n });\n\n controller.A.onEvent(SYSTEM_KEY_DOWN, () => {\n this.confirm();\n });\n\n controller.B.onEvent(SYSTEM_KEY_DOWN, () => {\n this.delete();\n });\n\n\n this.frameCount = 0;\n this.blink = true;\n\n game.onUpdate(() => {\n this.frameCount = (this.frameCount + 1) % 30;\n\n if (this.frameCount === 0) {\n this.blink = !this.blink;\n\n this.updateSelectedInput();\n }\n })\n }\n\n private moveVertical(up: boolean) {\n if (up) {\n if (this.cursorRow === 3) {\n this.cursor.image.fill(this.theme.colorCursor);\n this.cursorRow = 2;\n\n if (this.cursorColumn % 2) {\n this.cursorColumn = ALPHABET_ROW_LENGTH - 1;\n }\n else {\n this.cursorColumn = 0;\n }\n\n this.updateButtons();\n }\n else {\n this.cursorRow = Math.max(0, this.cursorRow - 1);\n }\n }\n else {\n this.cursorRow = Math.min(3, this.cursorRow + 1);\n\n if (this.cursorRow === 3) {\n // Go to closest button\n this.cursorColumn = this.cursorColumn > 5 ? 1 : 0;\n }\n }\n\n this.updateCursor();\n }\n\n private moveHorizontal(right: boolean) {\n if (right) {\n this.cursorColumn = (this.cursorColumn + 1) % ALPHABET_ROW_LENGTH;\n }\n else {\n this.cursorColumn = (this.cursorColumn + (ALPHABET_ROW_LENGTH - 1)) % ALPHABET_ROW_LENGTH;\n }\n\n this.updateCursor();\n }\n\n private confirm() {\n if (this.cursorRow === 3) {\n if (this.cursorColumn % 2) {\n this.confirmPressed = true;\n }\n else {\n this.upper = !this.upper;\n this.updateKeyboard();\n this.updateButtons();\n }\n }\n else {\n if (this.inputIndex >= this.answerLength) return;\n\n const index = this.cursorColumn + this.cursorRow * ALPHABET_ROW_LENGTH\n const letter = getCharForIndex(index, this.upper);\n\n if (!this.result) {\n this.result = letter;\n }\n else {\n this.result += letter;\n }\n\n const sprite = this.inputs[this.inputIndex];\n this.changeInputIndex(1);\n this.drawInput(sprite.image, letter, this.theme.colorInput);\n }\n }\n\n private delete() {\n if (this.inputIndex <= 0) return;\n\n if (this.inputIndex < this.answerLength) {\n this.drawInput(this.inputs[this.inputIndex].image, \"\", this.theme.colorInput);\n }\n\n this.result = this.result.substr(0, this.result.length - 1);\n\n this.changeInputIndex(-1);\n }\n\n private changeInputIndex(delta: number) {\n this.inputIndex += delta;\n this.frameCount = 0\n this.blink = false;\n this.updateSelectedInput();\n }\n }\n\n function layoutText(message: string, width: number, height: number, color: number) {\n const lineHeight = font.charHeight + PROMPT_LINE_SPACING;\n\n const lineLength = Math.floor(width / font.charWidth);\n const numLines = Math.floor(height / lineHeight);\n\n let lines: string[] = [];\n let word: string;\n let line: string;\n\n let pushWord = () => {\n if (line) {\n if (line.length + word.length + 1 > lineLength) {\n lines.push(line);\n line = word;\n }\n else {\n line = line + \" \" + word;\n }\n }\n else {\n line = word;\n }\n\n word = null;\n }\n\n for (let l = 0; l < message.length; l++) {\n const char = message.charAt(l);\n\n if (char === \" \") {\n if (word) {\n pushWord();\n }\n else {\n word = \" \";\n }\n }\n else if (!word) {\n word = char;\n }\n else {\n word += char;\n }\n }\n\n if (word) {\n pushWord();\n }\n\n if (line) {\n lines.push(line);\n }\n\n let maxLineWidth = 0;\n for (let m = 0; m < lines.length; m++) {\n maxLineWidth = Math.max(maxLineWidth, lines[m].length);\n }\n\n const actualWidth = maxLineWidth * font.charWidth;\n const actualHeight = lines.length * lineHeight;\n\n const res = image.create(actualWidth, actualHeight);\n\n for (let n = 0; n < lines.length; n++) {\n if ((n + 1) > numLines) break;\n res.print(lines[n], 0, n * lineHeight, color, font);\n }\n\n return res;\n }\n\n function getCharForIndex(index: number, upper: boolean) {\n if (index < 26) {\n return String.fromCharCode(index + (upper ? 65 : 97));\n }\n else {\n if (upper) {\n return digitsUpper[index - 26];\n }\n else {\n return \"\" + (index - 26);\n }\n }\n }\n}",
1706
- "pxt.json": "{\n \"name\": \"game\",\n \"description\": \"The game and sprite library - beta\",\n \"dependencies\": {\n \"settings\": \"*\",\n \"screen\": \"*\",\n \"mixer\": \"*\",\n \"power\": \"*\"\n },\n \"files\": [\n \"ns.ts\",\n \"gameoverrides.ts\",\n \"basesprite.ts\",\n \"constants.ts\",\n \"controlleroverrides.ts\",\n \"controller.ts\",\n \"controllerbutton.ts\",\n \"hitbox.ts\",\n \"renderText.ts\",\n \"spritesay.ts\",\n \"sprites.ts\",\n \"sprite.ts\",\n \"extendableSprite.ts\",\n \"sprite.d.ts\",\n \"spritemap.ts\",\n \"spriteevents.ts\",\n \"spriteset.ts\",\n \"spritekind.ts\",\n \"metrics.ts\",\n \"obstacle.ts\",\n \"physics.ts\",\n \"info.ts\",\n \"background.ts\",\n \"tilemap.ts\",\n \"camera.ts\",\n \"renderable.ts\",\n \"scene.ts\",\n \"scenes.ts\",\n \"textDialogs.ts\",\n \"game.ts\",\n \"gameutil.ts\",\n \"prompt.ts\",\n \"numberprompt.ts\",\n \"ask.ts\",\n \"targetoverrides.cpp\",\n \"targetoverrides.ts\",\n \"controllerbuttons.cpp\",\n \"mathUtil.ts\",\n \"systemmenu.ts\",\n \"systemmenuicons.ts\",\n \"console.ts\",\n \"fieldeditors.ts\",\n \"particles.ts\",\n \"particlefactories.ts\",\n \"particleeffects.ts\",\n \"effects.ts\",\n \"texteffects.ts\",\n \"assetTemplates.ts\",\n \"animation.ts\",\n \"multiplayer.cpp\",\n \"multiplayer.ts\",\n \"keymap.cpp\",\n \"keymap.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1706
+ "pxt.json": "{\n \"name\": \"game\",\n \"description\": \"The game and sprite library - beta\",\n \"dependencies\": {\n \"settings\": \"*\",\n \"screen\": \"*\",\n \"mixer\": \"*\",\n \"power\": \"*\"\n },\n \"files\": [\n \"ns.ts\",\n \"gameoverrides.ts\",\n \"basesprite.ts\",\n \"constants.ts\",\n \"controlleroverrides.ts\",\n \"controller.ts\",\n \"controllerbutton.ts\",\n \"hitbox.ts\",\n \"renderText.ts\",\n \"spritesay.ts\",\n \"sprites.ts\",\n \"sprite.ts\",\n \"extendableSprite.ts\",\n \"sprite.d.ts\",\n \"spritemap.ts\",\n \"spriteevents.ts\",\n \"spriteset.ts\",\n \"spritekind.ts\",\n \"metrics.ts\",\n \"obstacle.ts\",\n \"physics.ts\",\n \"info.ts\",\n \"background.ts\",\n \"tilemap.ts\",\n \"camera.ts\",\n \"renderable.ts\",\n \"scene.ts\",\n \"scenes.ts\",\n \"textDialogs.ts\",\n \"game.ts\",\n \"gameutil.ts\",\n \"prompt.ts\",\n \"numberprompt.ts\",\n \"ask.ts\",\n \"targetoverrides.cpp\",\n \"targetoverrides.ts\",\n \"controllerbuttons.cpp\",\n \"mathUtil.ts\",\n \"systemmenu.ts\",\n \"systemmenuicons.ts\",\n \"console.ts\",\n \"fieldeditors.ts\",\n \"particles.ts\",\n \"particlefactories.ts\",\n \"particleeffects.ts\",\n \"effects.ts\",\n \"texteffects.ts\",\n \"assetTemplates.ts\",\n \"animation.ts\",\n \"multiplayer.cpp\",\n \"multiplayer.ts\",\n \"keymap.cpp\",\n \"keymap.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1707
1707
  "renderText.ts": "namespace sprites {\n export class RenderText {\n linebreaks: number[];\n font: image.Font;\n height: number;\n width: number;\n\n constructor(public text: string, maxWidth: number) {\n this.font = image.getFontForText(text);\n\n this.setMaxWidth(maxWidth);\n }\n\n draw(canvas: Image, left: number, top: number, color: number, lineStart?: number, lineEnd?: number) {\n if (lineStart === undefined) lineStart = 0;\n if (lineEnd === undefined) lineEnd = this.linebreaks.length + 1;\n\n for (let i = lineStart; i < lineEnd; i++) {\n this.drawLine(canvas, left, top, i, color);\n top += this.font.charHeight;\n }\n }\n\n drawLine(canvas: Image, left: number, top: number, lineIndex: number, color: number) {\n const start = this.lineStart(lineIndex);\n const end = this.lineEnd(lineIndex);\n\n for (let i = start; i < end; i++) {\n canvas.print(this.text.charAt(i), left, top, color, this.font);\n left += this.font.charWidth;\n }\n }\n\n drawPartial(canvas: Image, left: number, top: number, color: number, lengthToDraw: number, lineStart?: number, lineEnd?: number) {\n if (lineStart === undefined) lineStart = 0;\n if (lineEnd === undefined) lineEnd = this.linebreaks.length + 1;\n\n let currentTextIndex = 0;\n for (let i = lineStart; i < lineEnd; i++) {\n currentTextIndex = this.drawPartialLine(canvas, left, top, i, color, currentTextIndex, lengthToDraw);\n top += this.font.charHeight;\n if (currentTextIndex >= lengthToDraw) return false;\n }\n\n return true;\n }\n\n drawPartialLine(canvas: Image, left: number, top: number, lineIndex: number, color: number, currentTextIndex: number, lengthToDraw: number) {\n const start = this.lineStart(lineIndex);\n const end = this.lineEnd(lineIndex);\n\n for (let i = start; i < end; i++) {\n canvas.print(this.text.charAt(i), left, top, color, this.font);\n left += this.font.charWidth;\n\n if (currentTextIndex + (i - start) >= lengthToDraw) {\n return lengthToDraw;\n }\n }\n return currentTextIndex + end - start;\n }\n\n calculatePartialHeight(startLine: number, lengthToDraw: number) {\n if (this.linebreaks.length === 0) return this.font.charHeight;\n\n let current = 0;\n\n for (let i = startLine; i < this.linebreaks.length + 1; i++) {\n current += this.lineEnd(i) - this.lineStart(i);\n if (current > lengthToDraw) return (i - startLine + 1) * this.font.charHeight\n }\n return this.height;\n }\n\n lineHeight() {\n return this.font.charHeight;\n }\n\n setMaxWidth(maxWidth: number) {\n this.linebreaks = getLineBreaks(this.text, [Math.idiv(maxWidth, this.font.charWidth)]);\n this.height = (this.linebreaks.length + 1) * this.font.charHeight;\n\n this.width = 0;\n for (let i = 0; i < this.linebreaks.length + 1; i++) {\n this.width = Math.max(this.lineEnd(i) - this.lineStart(i), this.width);\n }\n this.width *= this.font.charWidth;\n }\n\n printableCharacters() {\n let total = 0;\n for (let i = 0; i < this.linebreaks.length + 1; i++) {\n total += this.lineEnd(i) - this.lineStart(i);\n }\n return total;\n }\n\n lineEnd(lineIndex: number) {\n const prevEnd = lineIndex > 0 ? this.linebreaks[lineIndex - 1] : 0;\n let end = lineIndex < this.linebreaks.length ? this.linebreaks[lineIndex] : this.text.length;\n let didMove = false;\n\n // Trim trailing whitespace\n while (end > prevEnd) {\n if (this.text.charCodeAt(end) <= 32) {\n end--;\n didMove = true\n }\n else if (this.text.charAt(end) === \"n\" && this.text.charAt(end - 1) === \"\\\\\" && end - 1 > prevEnd) {\n end -= 2;\n didMove = true\n }\n else {\n break;\n }\n }\n return didMove ? end + 1 : end;\n }\n\n lineStart(lineIndex: number) {\n let start = lineIndex > 0 ? this.linebreaks[lineIndex - 1] : 0;\n\n // Trim leading whitespace\n while (start < this.text.length) {\n if (this.text.charCodeAt(start) <= 32) {\n start ++;\n }\n else if (this.text.charAt(start) === \"\\\\\" && this.text.charAt(start + 1) === \"n\" && start + 1 < this.text.length) {\n start += 2;\n }\n else {\n break;\n }\n }\n\n return start;\n }\n\n widthOfLine(lineIndex: number, fullTextOffset?: number) {\n if (fullTextOffset != undefined) {\n return (Math.min(this.lineEnd(lineIndex), fullTextOffset + 1) - this.lineStart(lineIndex)) * this.font.charWidth;\n }\n return (this.lineEnd(lineIndex) - this.lineStart(lineIndex)) * this.font.charWidth;\n }\n\n widthOfLines(lineStartIndex: number, lineEndIndex: number, offset?: number) {\n if (this.linebreaks.length === 0) return this.widthOfLine(0, offset);\n\n let width = 0;\n let fullTextOffset: number;\n for (let i = lineStartIndex; i < Math.min(lineEndIndex, this.linebreaks.length + 1); i++) {\n if (offset != undefined) {\n fullTextOffset = this.lineStart(i) + offset;\n offset -= this.lineEnd(i) - this.lineStart(i);\n }\n if (fullTextOffset !== undefined && this.lineStart(i) > fullTextOffset) break;\n width = Math.max(width, this.widthOfLine(i, fullTextOffset));\n }\n return width;\n }\n }\n\n\n function isBreakCharacter(charCode: number) {\n return charCode <= 32 ||\n (charCode >= 58 && charCode <= 64) ||\n (charCode >= 91 && charCode <= 96) ||\n (charCode >= 123 && charCode <= 126);\n }\n\n function getLineBreaks(text: string, lineLengths: number[]): number[] {\n const result: number[] = [];\n\n let lastBreakLocation = 0;\n let lastBreak = 0;\n let line = 0;\n let lineLength = lineLengths[line];\n\n function nextLine() {\n line++;\n lineLength = lineLengths[line % lineLengths.length];\n }\n\n for (let index = 0; index < text.length; index++) {\n if (text.charAt(index) === \"\\n\") {\n result.push(index);\n index++;\n lastBreak = index;\n nextLine();\n }\n // Handle \\\\n in addition to \\n because that's how it gets converted from blocks\n else if (text.charAt(index) === \"\\\\\" && text.charAt(index + 1) === \"n\") {\n result.push(index);\n lastBreak = index;\n index += 2;\n nextLine();\n }\n else if (isBreakCharacter(text.charCodeAt(index))) {\n lastBreakLocation = index;\n }\n\n if (index - lastBreak === lineLength) {\n if (lastBreakLocation === index || lastBreakLocation <= lastBreak) {\n result.push(index);\n lastBreak = index;\n nextLine();\n }\n else {\n result.push(lastBreakLocation);\n lastBreak = lastBreakLocation;\n nextLine();\n }\n }\n }\n\n return result;\n }\n\n enum RenderTextAnimationState {\n Idle,\n Printing,\n Pausing\n }\n\n export class RenderTextAnimation {\n protected tickPeriod: number;\n protected state: RenderTextAnimationState;\n protected pageLine: number;\n protected timer: number;\n protected pauseMillis: number;\n protected onTickCB: () => void;\n protected onEndCB: () => void;\n protected prevOffset: number;\n\n constructor(public text: RenderText, public height: number) {\n this.state = RenderTextAnimationState.Idle;\n this.timer = -1;\n\n this.pageLine = 0;\n this.setPauseLength(1000);\n this.setTextSpeed(30);\n }\n\n start() {\n this.state = RenderTextAnimationState.Printing;\n this.timer = control.millis();\n }\n\n numPages() {\n const maxLinesPerPage = Math.idiv(this.height, this.text.lineHeight()) + 1;\n return Math.floor((this.text.linebreaks.length + 1) / maxLinesPerPage);\n }\n\n setPauseLength(millis: number) {\n this.pauseMillis = millis;\n }\n\n setTextSpeed(charactersPerSecond: number) {\n this.tickPeriod = 1000/ charactersPerSecond;\n }\n\n currentHeight() {\n const minHeight = this.text.lineHeight();\n const maxHeight = Math.max(\n Math.min(\n Math.idiv(this.height, this.text.lineHeight()) + 1,\n this.text.linebreaks.length + 1 - this.pageLine\n ) * this.text.lineHeight(),\n minHeight\n );\n\n\n if (this.state === RenderTextAnimationState.Printing) {\n return Math.max(Math.min(\n this.text.calculatePartialHeight(this.pageLine, this.currentOffset()),\n maxHeight\n ), minHeight)\n }\n else if (this.state === RenderTextAnimationState.Pausing) {\n return maxHeight\n }\n else {\n return 0;\n }\n }\n\n currentWidth() {\n return this.text.widthOfLines(\n this.pageLine,\n this.pageLine + Math.idiv(this.currentHeight(), this.text.lineHeight()) + 1,\n this.state === RenderTextAnimationState.Printing ? this.currentOffset() : undefined\n );\n }\n\n currentOffset() {\n return Math.idiv(control.millis() - this.timer, this.tickPeriod)\n }\n\n isDone() {\n return this.state === RenderTextAnimationState.Idle;\n }\n\n cancel() {\n this.state = RenderTextAnimationState.Idle;\n }\n\n onCharacterPrinted(cb: () => void) {\n this.onTickCB = cb;\n }\n\n onAnimationEnd(cb: () => void) {\n this.onEndCB = cb;\n }\n\n draw(canvas: Image, left: number, top: number, color: number) {\n if (this.state === RenderTextAnimationState.Idle) return;\n else if (this.state === RenderTextAnimationState.Printing) {\n const pageFinished = this.text.drawPartial(\n canvas,\n left,\n top,\n color,\n this.currentOffset(),\n this.pageLine,\n this.pageLine + Math.idiv(this.height, this.text.lineHeight()) + 1\n );\n\n if (this.onTickCB && this.prevOffset !== this.currentOffset()) {\n this.onTickCB();\n }\n\n if (pageFinished) {\n this.state = RenderTextAnimationState.Pausing;\n this.timer = this.pauseMillis\n }\n }\n else {\n this.text.draw(\n canvas,\n left,\n top,\n color,\n this.pageLine,\n this.pageLine + Math.idiv(this.height, this.text.lineHeight()) + 1\n );\n\n this.timer -= game.currentScene().eventContext.deltaTimeMillis;\n\n if (this.timer < 0) {\n this.pageLine += Math.idiv(this.height, this.text.lineHeight()) + 1;\n if (this.pageLine > this.text.linebreaks.length) {\n this.state = RenderTextAnimationState.Idle;\n if (this.onEndCB) this.onEndCB();\n }\n else {\n this.state = RenderTextAnimationState.Printing;\n this.timer = control.millis();\n }\n }\n }\n\n this.prevOffset = this.currentOffset();\n }\n }\n}",
1708
1708
  "renderable.ts": "namespace scene {\n export class Renderable extends sprites.BaseSprite {\n public constructor(\n protected handler: (target: Image, camera: Camera) => void,\n protected shouldBeVisible: () => boolean,\n z: number,\n ) {\n super(z);\n }\n\n __visible(): boolean {\n return this.shouldBeVisible();\n }\n\n __drawCore(camera: scene.Camera) {\n this.handler(screen, camera);\n }\n\n destroy() {\n const s = game.currentScene();\n s.allSprites.removeElement(this);\n }\n }\n\n export function createRenderable(\n z: number,\n handler: (target: Image, camera: Camera) => void,\n shouldBeVisible?: () => boolean\n ): Renderable {\n const renderable = new Renderable(\n handler,\n shouldBeVisible || (() => true),\n z,\n );\n\n return renderable;\n }\n}",
1709
1709
  "scene.ts": "interface SparseArray<T> {\n [index: number]: T;\n}\n\n/**\n * Control the background, tiles and camera\n */\nnamespace scene {\n export enum Flag {\n NeedsSorting = 1 << 0, // indicates the sprites in the scene need to be sorted before rendering\n SeeThrough = 1 << 1, // if set, render the previous scene 'below' this one as the background\n IsRendering = 1 << 2, // if set, the scene is currently being rendered to the screen\n }\n\n export class SpriteHandler {\n constructor(\n public kind: number,\n public handler: (sprite: Sprite) => void\n ) { }\n }\n\n export class OverlapHandler {\n constructor(\n public kind: number,\n public otherKind: number,\n public handler: (sprite: Sprite, otherSprite: Sprite) => void\n ) { }\n }\n\n export class TileWallHandler {\n constructor(\n public spriteKind: number,\n public handler: (sprite: Sprite, location: tiles.Location) => void\n ) { }\n }\n\n export class TileOverlapHandler {\n constructor(\n public spriteKind: number,\n public tileKind: Image,\n public handler: (sprite: Sprite, location: tiles.Location) => void\n ) { }\n }\n\n\n export class GameForeverHandler {\n public lock: boolean;\n constructor(\n public handler: () => void\n ) { }\n }\n\n // frame handler priorities\n export const CONTROLLER_PRIORITY = 8;\n export const UPDATE_CONTROLLER_PRIORITY = 13;\n export const FOLLOW_SPRITE_PRIORITY = 14;\n export const PHYSICS_PRIORITY = 15;\n export const ANIMATION_UPDATE_PRIORITY = 15;\n export const CONTROLLER_SPRITES_PRIORITY = 13;\n export const UPDATE_INTERVAL_PRIORITY = 19;\n export const UPDATE_PRIORITY = 20;\n export const PRE_RENDER_UPDATE_PRIORITY = 55;\n export const RENDER_BACKGROUND_PRIORITY = 60;\n export const RENDER_SPRITES_PRIORITY = 90;\n export const RENDER_DIAGNOSTICS_PRIORITY = 150;\n export const MULTIPLAYER_SCREEN_PRIORITY = 190;\n export const UPDATE_SCREEN_PRIORITY = 200;\n export const MULTIPLAYER_POST_SCREEN_PRIORITY = 210;\n\n // default rendering z indices\n export const ON_PAINT_Z = -20;\n export const TILE_MAP_Z = -1;\n export const SPRITE_Z = 0;\n export const ON_SHADE_Z = 80;\n export const HUD_Z = 100;\n\n export class Scene {\n eventContext: control.EventContext;\n background: Background;\n tileMap: tiles.TileMap;\n allSprites: SpriteLike[];\n private spriteNextId: number;\n spritesByKind: SparseArray<sprites.SpriteSet>;\n physicsEngine: PhysicsEngine;\n camera: scene.Camera;\n flags: number;\n destroyedHandlers: SpriteHandler[];\n createdHandlers: SpriteHandler[];\n overlapHandlers: OverlapHandler[];\n overlapMap: SparseArray<number[]>;\n tileOverlapHandlers: TileOverlapHandler[];\n collisionHandlers: SpriteHandler[][];\n wallCollisionHandlers: TileWallHandler[];\n gameForeverHandlers: GameForeverHandler[];\n particleSources: particles.ParticleSource[];\n controlledSprites: controller.ControlledSprite[][];\n followingSprites: sprites.FollowingSprite[];\n buttonEventHandlers: controller.ButtonEventHandlerState[];\n\n private _millis: number;\n private _data: any;\n\n // a set of functions that need to be called when a scene is being initialized\n static initializers: ((scene: Scene) => void)[] = [];\n\n constructor(eventContext: control.EventContext, protected previousScene?: Scene) {\n this.eventContext = eventContext;\n this.flags = 0;\n this.physicsEngine = new ArcadePhysicsEngine();\n this.camera = new scene.Camera();\n this.background = new Background(this.camera);\n this.destroyedHandlers = [];\n this.createdHandlers = [];\n this.overlapHandlers = [];\n this.overlapMap = {};\n this.tileOverlapHandlers = [];\n this.collisionHandlers = [];\n this.wallCollisionHandlers = [];\n this.gameForeverHandlers = [];\n this.spritesByKind = {};\n this.controlledSprites = [];\n this.buttonEventHandlers = [];\n this._data = {};\n this._millis = 0;\n }\n\n init() {\n if (this.allSprites) return;\n\n power.poke(); // keep game alive a little more\n this.allSprites = [];\n this.spriteNextId = 0;\n // update controller state\n this.eventContext.registerFrameHandler(CONTROLLER_PRIORITY, () => {\n this._millis += this.eventContext.deltaTimeMillis;\n control.enablePerfCounter(\"controller_update\")\n controller.__update(this.eventContext.deltaTime);\n })\n // controller update 13\n this.eventContext.registerFrameHandler(CONTROLLER_SPRITES_PRIORITY, controller._moveSprites);\n // sprite following 14\n // apply physics and collisions 15\n this.eventContext.registerFrameHandler(PHYSICS_PRIORITY, () => {\n control.enablePerfCounter(\"physics and collisions\")\n this.physicsEngine.move(this.eventContext.deltaTime);\n });\n // user update interval 19s\n\n // user update 20\n\n // prerender update 55\n this.eventContext.registerFrameHandler(PRE_RENDER_UPDATE_PRIORITY, () => {\n const dt = this.eventContext.deltaTime;\n this.camera.update();\n\n for (const s of this.allSprites)\n s.__update(this.camera, dt);\n })\n\n // render background 60\n\n // render 90\n this.eventContext.registerFrameHandler(RENDER_SPRITES_PRIORITY, () => {\n control.enablePerfCounter(\"scene_draw\");\n this.render();\n });\n // render diagnostics\n this.eventContext.registerFrameHandler(RENDER_DIAGNOSTICS_PRIORITY, () => {\n if (game.stats && control.EventContext.onStats) {\n control.EventContext.onStats(\n control.EventContext.lastStats +\n ` sprites:${this.allSprites.length}`\n )\n }\n if (game.debug)\n this.physicsEngine.draw();\n game.consoleOverlay.draw();\n // check for power deep sleep\n power.checkDeepSleep();\n });\n // update screen\n this.eventContext.registerFrameHandler(UPDATE_SCREEN_PRIORITY, control.__screen.update);\n multiplayer.initServer();\n // register additional components\n Scene.initializers.forEach(f => f(this));\n }\n\n get data() {\n return this._data;\n }\n\n /**\n * Gets the elapsed time in the scene\n */\n millis(): number {\n return this._millis;\n }\n\n addSprite(sprite: SpriteLike) {\n this.allSprites.push(sprite);\n sprite.id = this.spriteNextId++;\n }\n\n destroy() {\n this.eventContext = undefined;\n this.background = undefined;\n this.tileMap = undefined;\n this.allSprites = undefined;\n this.spriteNextId = undefined;\n this.spritesByKind = undefined;\n this.physicsEngine = undefined;\n this.camera = undefined;\n this.flags = undefined;\n this.destroyedHandlers = undefined;\n this.createdHandlers = undefined;\n this.overlapHandlers = undefined;\n this.tileOverlapHandlers = undefined;\n this.collisionHandlers = undefined;\n this.wallCollisionHandlers = undefined;\n this.gameForeverHandlers = undefined;\n this._data = undefined;\n }\n\n /**\n * Renders the current frame as an image\n */\n render() {\n // bail out from recursive or parallel call.\n if (this.flags & scene.Flag.IsRendering) return;\n this.flags |= scene.Flag.IsRendering;\n\n control.enablePerfCounter(\"render background\")\n if ((this.flags & scene.Flag.SeeThrough) && this.previousScene) {\n this.previousScene.render();\n } else {\n this.background.draw();\n }\n\n control.enablePerfCounter(\"sprite sort\")\n if (this.flags & Flag.NeedsSorting) {\n this.allSprites.sort(function (a, b) { return a.z - b.z || a.id - b.id; })\n this.flags &= ~scene.Flag.NeedsSorting;\n }\n\n control.enablePerfCounter(\"sprite draw\")\n for (const s of this.allSprites) {\n s.__draw(this.camera);\n }\n\n this.flags &= ~scene.Flag.IsRendering;\n }\n }\n}\n",
@@ -1733,26 +1733,26 @@ var pxtTargetBundle = {
1733
1733
  "controlleroverrides.ts": "namespace controller {\n //% fixedInstance whenUsed block=\"{id:controller}A\"\n export const A = new Button(ControllerButton.A, DAL.CFG_PIN_BTN_A);\n //% fixedInstance whenUsed block=\"{id:controller}B\"\n export const B = new Button(ControllerButton.B, DAL.CFG_PIN_BTN_B);\n //% fixedInstance whenUsed block=\"left\"\n export const left = new Button(ControllerButton.Left, DAL.CFG_PIN_BTN_LEFT);\n //% fixedInstance whenUsed block=\"up\"\n export const up = new Button(ControllerButton.Up, DAL.CFG_PIN_BTN_UP);\n //% fixedInstance whenUsed block=\"right\"\n export const right = new Button(ControllerButton.Right, DAL.CFG_PIN_BTN_RIGHT);\n //% fixedInstance whenUsed block=\"down\"\n export const down = new Button(ControllerButton.Down, DAL.CFG_PIN_BTN_DOWN);\n //% fixedInstance whenUsed block=\"menu\"\n export const menu = new Button(7, DAL.CFG_PIN_BTN_MENU);\n\n //% fixedInstance whenUsed block=\"player 2\"\n export const player2 = new Controller(2, undefined);\n //% fixedInstance whenUsed block=\"player 3\"\n export const player3 = new Controller(3, undefined);\n //% fixedInstance whenUsed block=\"player 4\"\n export const player4 = new Controller(4, undefined);\n //% fixedInstance whenUsed block=\"player 1\"\n export const player1 = controller._player1();\n}",
1734
1734
  "gameutil.ts": "/**\n * Game transitions and dialog\n **/\nnamespace game {\n\n /**\n * Update the position and velocities of sprites\n * @param body code to execute\n */\n //% group=\"Gameplay\"\n //% help=game/on-update weight=100 afterOnStart=true\n //% blockId=gameupdate block=\"on game update\"\n //% blockAllowMultiple=1\n export function onUpdate(a: () => void): void {\n if (!a) return;\n game.eventContext().registerFrameHandler(scene.UPDATE_PRIORITY, a);\n }\n\n /**\n * Run code on an interval of time. This executes before game.onUpdate()\n * @param body code to execute\n */\n //% group=\"Gameplay\"\n //% help=game/on-update-interval weight=99 afterOnStart=true\n //% blockId=gameinterval block=\"on game update every %period=timePicker ms\"\n //% blockAllowMultiple=1\n export function onUpdateInterval(period: number, a: () => void): void {\n if (!a || period < 0) return;\n let timer = 0;\n game.eventContext().registerFrameHandler(scene.UPDATE_INTERVAL_PRIORITY, () => {\n const time = game.currentScene().millis();\n if (timer <= time) {\n timer = time + period;\n a();\n }\n });\n }\n\n /**\n * Returns the time since the game started in milliseconds\n */\n //% blockId=arcade_game_runtime block=\"time since start (ms)\"\n //% group=\"Gameplay\" weight=11\n //% help=game/runtime\n export function runtime(): number {\n return currentScene().millis();\n }\n}\n",
1735
1735
  "mathUtil.ts": "namespace Math {\n /**\n * Returns a random boolean that is true the given percentage of the time.\n * @param percentage The percentage chance that the returned value will be true from 0 - 100\n */\n //% weight=2\n //% blockId=percentchance block=\"%percentage|\\\\% chance\"\n //% percentage.min=0 percentage.max=100;\n //% help=math/percent-chance\n export function percentChance(percentage: number): boolean {\n if (percentage >= 100) {\n return true;\n }\n else if (percentage <= 0) {\n return false;\n }\n return Math.randomRange(0, 99) < percentage;\n }\n\n /**\n * Returns a random element from the given list\n * @param list The list to choose an element from\n */\n //% weight=1\n export function pickRandom<T>(list: T[]) {\n if (!list || list.length == 0) {\n return undefined;\n }\n return list[Math.randomRange(0, list.length - 1)];\n }\n\n /**\n * Fast, 16 bit, seedable (pseudo) random generator.\n */\n export class FastRandom {\n // Implementation of the Galois Linear Feedback Shift Register\n private lfsr: number;\n // A value between 0x0001 and 0xFFFF to generate random values from\n public seed: number;\n\n /**\n * Create a new Fast Random generator\n * @param seed [Optional] initial seed between 0x0001 and 0xFFFF.\n */\n constructor(seed?: number) {\n if (seed === undefined) seed = Math.randomRange(0x0001, 0xFFFF);\n this.seed = seed;\n this.lfsr = seed;\n }\n\n /**\n * @returns the next random number between 0x0001 and 0xFFFF inclusive\n */\n next(): number {\n return this.lfsr = (this.lfsr >> 1) ^ ((-(this.lfsr & 1)) & 0xb400);\n }\n\n /**\n * @param min the minimum value to generate\n * @param max the maximum value to generate\n * @returns a random value between min and max (inclusive). If min is greater than or equal to max, returns min.\n */\n randomRange(min: number, max: number): number {\n return min + (max > min ? this.next() % (max - min + 1) : 0);\n }\n\n /**\n * Returns a random element from the given list\n * @param list The list to choose an element from\n */\n pickRandom<T>(list: T[]) {\n if (!list || list.length == 0) {\n return undefined;\n }\n return list[this.randomRange(0, list.length - 1)];\n }\n\n /**\n * @returns a random boolean value\n */\n randomBool(): boolean {\n return !(this.next() & 1);\n }\n\n /**\n * @param percent the percentage chance that the returned value will be true from 0 - 100\n * @returns a boolean with approximately the given percent chance to be true or false\n */\n percentChance(percent: number): boolean {\n return this.randomRange(0, 100) < percent;\n }\n\n /**\n * Reset the state to the current seed\n */\n reset() {\n this.lfsr = this.seed;\n }\n }\n}\n",
1736
- "pxt.json": "{\n \"name\": \"game---light\",\n \"description\": \"Empty game library - beta\",\n \"dependencies\": {\n \"settings\": \"*\",\n \"screen\": \"*\"\n },\n \"files\": [\n \"compat.ts\",\n \"console.ts\",\n \"constants.ts\",\n \"controlleroverrides.ts\",\n \"controllerbutton.ts\",\n \"controllerbuttons.cpp\",\n \"mathUtil.ts\",\n \"gameutil.ts\",\n \"targetoverrides.cpp\",\n \"targetoverrides.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1736
+ "pxt.json": "{\n \"name\": \"game---light\",\n \"description\": \"Empty game library - beta\",\n \"dependencies\": {\n \"settings\": \"*\",\n \"screen\": \"*\"\n },\n \"files\": [\n \"compat.ts\",\n \"console.ts\",\n \"constants.ts\",\n \"controlleroverrides.ts\",\n \"controllerbutton.ts\",\n \"controllerbuttons.cpp\",\n \"mathUtil.ts\",\n \"gameutil.ts\",\n \"targetoverrides.cpp\",\n \"targetoverrides.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1737
1737
  "targetoverrides.cpp": "// Overriden in target\n",
1738
1738
  "targetoverrides.ts": "// Overriden in target\n"
1739
1739
  },
1740
1740
  "hw": {
1741
1741
  "basepins.d.ts": "//% advanced=true\ndeclare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_LED)\n const LED: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SDA)\n const SDA: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCL)\n const SCL: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCK)\n const SCK: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MISO)\n const MISO: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MOSI)\n const MOSI: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_RX)\n const RX: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_TX)\n const TX: DigitalInOutPin;\n}\n",
1742
1742
  "config.ts": "namespace config {\n export const DISPLAY_WIDTH = 160;\n export const DISPLAY_HEIGHT = 120;\n}\n",
1743
- "pxt.json": "{\n \"name\": \"hw\",\n \"description\": \"Hardware definition - web-browser only\",\n \"dependencies\": {\n \"core\": \"*\",\n \"screen\": \"*\",\n \"mixer\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"basepins.d.ts\",\n \"config.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"skipLocalization\": true\n}\n"
1743
+ "pxt.json": "{\n \"name\": \"hw\",\n \"description\": \"Hardware definition - web-browser only\",\n \"dependencies\": {\n \"core\": \"*\",\n \"screen\": \"*\",\n \"mixer\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"basepins.d.ts\",\n \"config.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"skipLocalization\": true\n}\n"
1744
1744
  },
1745
1745
  "hw---n3": {
1746
1746
  "basepins.d.ts": "//% advanced=true\ndeclare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_LED)\n const LED: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SDA)\n const SDA: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCL)\n const SCL: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCK)\n const SCK: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MISO)\n const MISO: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MOSI)\n const MOSI: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_RX)\n const RX: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_TX)\n const TX: DigitalInOutPin;\n}\n",
1747
1747
  "config.ts": "// there's no UF2 bootloader for 52833 yet, so we specify example configuration here\nnamespace config {\n export const PIN_BTNMX_LATCH = DAL.P0_9\n export const PIN_BTNMX_CLOCK = DAL.P1_0\n export const PIN_BTNMX_DATA = DAL.P0_1\n\n // pybadge-like layout\n export const PIN_BTN_LEFT = 1050\n export const PIN_BTN_UP = 1051\n export const PIN_BTN_DOWN = 1052\n export const PIN_BTN_RIGHT = 1053\n export const PIN_BTN_A = 1054\n export const PIN_BTN_B = 1055\n export const PIN_BTN_MENU = 1056\n\n export const PIN_JACK_SND = DAL.P0_0\n\n export const PIN_DISPLAY_SCK = DAL.P0_17\n export const PIN_DISPLAY_MOSI = DAL.P0_13\n export const PIN_DISPLAY_MISO = DAL.P0_1\n export const PIN_DISPLAY_BL = DAL.P0_26\n export const PIN_DISPLAY_DC = DAL.P0_10\n export const PIN_DISPLAY_RST = DAL.P1_2\n\n // Jacdac, when jacdaptor is connected, is on the accessibility pin (P12)\n export const PIN_JACK_TX = DAL.P0_12\n\n export const DISPLAY_WIDTH = 160\n export const DISPLAY_HEIGHT = 128\n\n export const DISPLAY_TYPE = 4242 // smart display\n\n export const DISPLAY_CFG0 = 0x00000080\n export const DISPLAY_CFG1 = 0x00000603\n export const DISPLAY_CFG2 = 8\n}\n",
1748
1748
  "device.d.ts": "// nothing here yet",
1749
- "pxt.json": "{\n \"name\": \"hw---n3\",\n \"description\": \"NRF52833 board\",\n \"dependencies\": {\n \"core---nrf52\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---nrf52\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"N3\",\n \"description\": \"Board based on Nordic NRF52833\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#n3\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEX/gTX///8knKOkg58AAADai7jeAAAB3UlEQVRo3u2Wi3HDIAxAzQaWNhArNBuk+89U9ImNHahdrCZOgs7Hid9DEmAxfDnL0IEd+EDg93deqhwBXgCuWalyfXdgipkvMAEUKJsiC3gBpxCcDsiOXu1UOgAZYpjLpB06NpdXAzrc5XxTbrrH1VscnA58V6BmFPc/tnuSOn71zg0sJPr+WOrADuzADnwxYHSWDvxUIM4qxQj33QTSLAoByjhUZQuISHlV1iCZnj5TpBExUm4hcHcqb59ahwLD9XKoHFN0LNkkA3IHGzOtPbkRbeFZALiZVBGyKrbyDJSpBkSOkVmIsWwhTqaaNzmQXY65y+IAoMS96HLqR/Eg25R+sN8SSPL6R0fg+qaeEAhywNuB5A7ENuB657JtbYshxioQvYHgBIRJsNB4CAj3uYeOAdEbCO5AfLqFfNgAPGNYyO7tuwxg+TkurCyew11Ayc/2BKGNm7IfSBRrQGwC6tAiMLYBYw2IDcA5/LTxx94HrP/wqw/TxwKheMkOAP8iHXhC4P6s15/ETwZ2+UcJi9pY73okMMAwjlzax5SgLVyO1njrUoUH1GQMAwQ2Jin8AU8Koic1VZddWuUBvwDHYZ4FbJ8Bkxmw7toGBrFhdlk8ShHj9jDHYaHIgM+WH/pHX7EAVIxFAAAAAElFTkSuQmCC\"\n },\n \"compileServiceVariant\": \"nrf52833\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 0,\n \"DEVICE_WEBUSB\": 0\n }\n },\n \"experimentalHw\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---nrf52\"\n }\n}\n"
1749
+ "pxt.json": "{\n \"name\": \"hw---n3\",\n \"description\": \"NRF52833 board\",\n \"dependencies\": {\n \"core---nrf52\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---nrf52\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"N3\",\n \"description\": \"Board based on Nordic NRF52833\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#n3\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEX/gTX///8knKOkg58AAADai7jeAAAB3UlEQVRo3u2Wi3HDIAxAzQaWNhArNBuk+89U9ImNHahdrCZOgs7Hid9DEmAxfDnL0IEd+EDg93deqhwBXgCuWalyfXdgipkvMAEUKJsiC3gBpxCcDsiOXu1UOgAZYpjLpB06NpdXAzrc5XxTbrrH1VscnA58V6BmFPc/tnuSOn71zg0sJPr+WOrADuzADnwxYHSWDvxUIM4qxQj33QTSLAoByjhUZQuISHlV1iCZnj5TpBExUm4hcHcqb59ahwLD9XKoHFN0LNkkA3IHGzOtPbkRbeFZALiZVBGyKrbyDJSpBkSOkVmIsWwhTqaaNzmQXY65y+IAoMS96HLqR/Eg25R+sN8SSPL6R0fg+qaeEAhywNuB5A7ENuB657JtbYshxioQvYHgBIRJsNB4CAj3uYeOAdEbCO5AfLqFfNgAPGNYyO7tuwxg+TkurCyew11Ayc/2BKGNm7IfSBRrQGwC6tAiMLYBYw2IDcA5/LTxx94HrP/wqw/TxwKheMkOAP8iHXhC4P6s15/ETwZ2+UcJi9pY73okMMAwjlzax5SgLVyO1njrUoUH1GQMAwQ2Jin8AU8Koic1VZddWuUBvwDHYZ4FbJ8Bkxmw7toGBrFhdlk8ShHj9jDHYaHIgM+WH/pHX7EAVIxFAAAAAElFTkSuQmCC\"\n },\n \"compileServiceVariant\": \"nrf52833\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 0,\n \"DEVICE_WEBUSB\": 0\n }\n },\n \"experimentalHw\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---nrf52\"\n }\n}\n"
1750
1750
  },
1751
1751
  "hw---n4": {
1752
1752
  "basepins.d.ts": "//% advanced=true\ndeclare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_LED)\n const LED: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SDA)\n const SDA: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCL)\n const SCL: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCK)\n const SCK: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MISO)\n const MISO: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MOSI)\n const MOSI: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_RX)\n const RX: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_TX)\n const TX: DigitalInOutPin;\n}\n",
1753
1753
  "config.ts": "namespace config {\n // all should be in bootloader\n}\n",
1754
1754
  "device.d.ts": "// nothing here yet",
1755
- "pxt.json": "{\n \"name\": \"hw---n4\",\n \"description\": \"NRF52840 board\",\n \"dependencies\": {\n \"core---nrf52\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---nrf52\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"N4\",\n \"description\": \"Board based on Nordic NRF52840\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#n4\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEX/gTUAP63///+kg58AAADcmUjBAAAB50lEQVRo3u2YC3KEIAxAHW4AJzC5Qr2B3P9MJSGIulgtZl1byThs+D2S8G27L2XpGrABLwR6n9O5VgscEMeU5vx/B4aoTRjvFYABkYAx9wRgihz9qkyKYIaMPrdshgwchzsD2V2dnZJQ8yV+fuutNuE9gd6T8/FEVAEmGRuw8sT2XndSHnNJqV/07fXVgA3YgA14OdAqSwM+FQhZddbia7VDLmbFIXA7oLb7QAA3z/IYjrrTJwoXAsjIAkSqDmn6rIwKS34cDiJHlNjWMWACUgUZM40tblBrt7IfkYpdVJgcFVgDuasAgWIkFoItWwiTqRGAHMyZy3buMnuNwHEvuhzqgT04Miltp/xloOO/n0ARuN6pNwQiL/B6oFMHQh1wPXOzaa2LIdhNIGgDUQmY/w0AhcJTQHy9e9w5IGgDUR0IH7eQFhuiZgwLt3v9LCPK/WwXVhbX4SEg38/yBHE7O+U4MD5TikCoAsamRaCtA9otIFQAc/jdzol9DLh94G8+TK8FYnGTnQD+RhrwhsDjt157En8Y2OSNYha5frvqSqDBru8plY8oJpZQ2kthqooKNdiS3nRoyJig0IfUybAe1JBdVsUsNfgB2He5F5J9Agxm4LpqH2jYhuwyexQiRuUmx2GhcINnyzfOJXvHTJa1sgAAAABJRU5ErkJggg==\"\n },\n \"compileServiceVariant\": \"nrf52840\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 0,\n \"DEVICE_WEBUSB\": 0\n }\n },\n \"experimentalHw\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---nrf52\"\n }\n}\n"
1755
+ "pxt.json": "{\n \"name\": \"hw---n4\",\n \"description\": \"NRF52840 board\",\n \"dependencies\": {\n \"core---nrf52\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---nrf52\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"N4\",\n \"description\": \"Board based on Nordic NRF52840\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#n4\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEX/gTUAP63///+kg58AAADcmUjBAAAB50lEQVRo3u2YC3KEIAxAHW4AJzC5Qr2B3P9MJSGIulgtZl1byThs+D2S8G27L2XpGrABLwR6n9O5VgscEMeU5vx/B4aoTRjvFYABkYAx9wRgihz9qkyKYIaMPrdshgwchzsD2V2dnZJQ8yV+fuutNuE9gd6T8/FEVAEmGRuw8sT2XndSHnNJqV/07fXVgA3YgA14OdAqSwM+FQhZddbia7VDLmbFIXA7oLb7QAA3z/IYjrrTJwoXAsjIAkSqDmn6rIwKS34cDiJHlNjWMWACUgUZM40tblBrt7IfkYpdVJgcFVgDuasAgWIkFoItWwiTqRGAHMyZy3buMnuNwHEvuhzqgT04Miltp/xloOO/n0ARuN6pNwQiL/B6oFMHQh1wPXOzaa2LIdhNIGgDUQmY/w0AhcJTQHy9e9w5IGgDUR0IH7eQFhuiZgwLt3v9LCPK/WwXVhbX4SEg38/yBHE7O+U4MD5TikCoAsamRaCtA9otIFQAc/jdzol9DLh94G8+TK8FYnGTnQD+RhrwhsDjt157En8Y2OSNYha5frvqSqDBru8plY8oJpZQ2kthqooKNdiS3nRoyJig0IfUybAe1JBdVsUsNfgB2He5F5J9Agxm4LpqH2jYhuwyexQiRuUmx2GhcINnyzfOJXvHTJa1sgAAAABJRU5ErkJggg==\"\n },\n \"compileServiceVariant\": \"nrf52840\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 0,\n \"DEVICE_WEBUSB\": 0\n }\n },\n \"experimentalHw\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---nrf52\"\n }\n}\n"
1756
1756
  },
1757
1757
  "hw---rpi": {
1758
1758
  "config.ts": "\nnamespace config {\n export const DISPLAY_WIDTH = 160;\n export const DISPLAY_HEIGHT = 120;\n}\n",
@@ -1760,32 +1760,32 @@ var pxtTargetBundle = {
1760
1760
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum Key {\n LEFT = 1,\n UP = 2,\n RIGHT = 3,\n DOWN = 4,\n A = 5,\n B = 6,\n MENU = 7,\n LEFT2 = 8,\n UP2 = 9,\n RIGHT2 = 10,\n DOWN2 = 11,\n A2 = 12,\n B2 = 13,\n RESET = 14,\n EXIT = 15,\n }\n\n// Auto-generated. Do not edit. Really.\n",
1761
1761
  "gamesel.cpp": "#include \"pxt.h\"\n\n#include <sys/types.h>\n#include <dirent.h>\n#include <sys/stat.h>\n#include <stdio.h>\n#include <unistd.h>\n\nnamespace control {\n\n\n//%\nRefCollection *programList() {\n DIR *d = opendir(PROGDIR);\n auto res = Array_::mk();\n registerGCObj(res);\n for (;;) {\n struct dirent *ent = readdir(d);\n if (!ent)\n break;\n int len = strlen(ent->d_name);\n if (len <= 4)\n continue;\n if (strcmp(ent->d_name + len - 4, \".elf\") != 0)\n continue;\n ent->d_name[len - 4] = 0; // chop extension\n //DMESG(\"add: '%s'\", ent->d_name);\n auto tmp = (TValue)mkString(ent->d_name, -1);\n registerGCPtr(tmp);\n res->head.push(tmp);\n unregisterGCPtr(tmp);\n }\n closedir(d);\n unregisterGCObj(res);\n return res;\n}\n\n/** Run specified user program. */\n//%\nvoid runProgram(String prog) {\n char *p;\n asprintf(&p, \"%s/%s.elf\", PROGDIR, prog->getUTF8Data());\n initialArgv = new char*[3];\n initialArgv[0] = p;\n initialArgv[1] = (char*)\"--run\";\n initialArgv[2] = 0;\n target_reset();\n}\n\n/**\n * Deletes a user program\n */\n//%\nvoid deleteProgram(String prog) {\n char *p;\n asprintf(&p, \"%s/%s.elf\", PROGDIR, prog->getUTF8Data());\n unlink(p);\n}\n\n} // namespace control\n",
1762
1762
  "keys.cpp": "#include \"pxt.h\"\n\n#include <wiringPi.h>\n#include <wiringPiI2C.h>\n#include <pthread.h>\n\n#include <linux/input.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\nnamespace music {\nvoid playTone(int frequency, int ms);\n}\n\nnamespace pxt {\n\nenum class Key {\n LEFT = 1,\n UP,\n RIGHT,\n DOWN,\n A,\n B,\n MENU,\n LEFT2,\n UP2,\n RIGHT2,\n DOWN2,\n A2,\n B2,\n RESET,\n EXIT,\n};\n\n/*\nBTN_A = 12, 16\nBTN_B = 6, 13\nBTN_MENU = 20\nBTN_EXIT = 22, 23\nBTN_RESTART = 26\nJOYSTICK_ADDR = 0x48\n# Free pins: 4, 5, 17, 24, 25, 27\n*/\n\nconst int INTERNAL_KEY_UP = 2050;\nconst int INTERNAL_KEY_DOWN = 2051;\n\nstatic int adcFD;\n\nstatic int useScanCodes, scanCodeFD;\n\n#define SWAP(v) (uint16_t)((v >> 8) | (v << 8))\n#define MID 0x3300\n#define DEAD 0x1000\n\nstatic int readADC(int channel) {\n if (!adcFD) {\n int addr = getConfigInt(\"JOYSTICK_ADDR\", -1);\n if (addr < 0)\n adcFD = -1;\n else\n adcFD = wiringPiI2CSetup(0x48);\n }\n\n if (adcFD < 0)\n return MID;\n\n uint16_t config = 0x8383;\n config += 0x4000 + 0x1000 * channel;\n\n wiringPiI2CWriteReg16(adcFD, 0x01, SWAP(config));\n sleep_core_us(1000);\n\n config = wiringPiI2CReadReg16(adcFD, 0x00);\n return SWAP(config);\n}\n\n#define SET(s) r |= 1 << (int)(Key::s)\n#define KEY(s) \\\n if (isPressed(\"BTN_\" #s, (int)Key::s)) \\\n SET(s)\n\nstatic uint8_t pressedScanCodes[1024];\n\nstatic int isPressed(const char *name, int keyPos) {\n static uint64_t parsedPin[(int)Key::EXIT + 1];\n\n if (useScanCodes) {\n auto pins = getConfigInts(name);\n for (int i = 0; pins[i] != ENDMARK; ++i) {\n auto p = pins[i];\n if (p < (int)sizeof(pressedScanCodes) && pressedScanCodes[p])\n return 1;\n }\n return 0;\n }\n\n if (parsedPin[keyPos] == 0) {\n auto pins = getConfigInts(name);\n for (int i = 0; pins[i] != ENDMARK; ++i) {\n auto p = pins[i];\n auto mask = 1ULL << p;\n parsedPin[keyPos] |= mask;\n pinMode(p, INPUT);\n pullUpDnControl(p, PUD_UP);\n }\n // make sure it's non-zero\n parsedPin[keyPos] |= 1ULL << 63;\n }\n\n for (int i = 0; i < 63; ++i) {\n if ((parsedPin[keyPos] >> i) & 1)\n if (!digitalRead(i))\n return 1;\n }\n\n return 0;\n}\n\nstatic void updateScanCodes() {\n if (!useScanCodes)\n return;\n\n struct input_event ev[64];\n int rd = read(scanCodeFD, ev, sizeof(ev));\n\n for (int i = 0; i < rd / (int)sizeof(struct input_event); i++) {\n if (ev[i].type == 1 && ev[i].code < sizeof(pressedScanCodes))\n pressedScanCodes[ev[i].code] = ev[i].value;\n }\n}\n\nstatic uint16_t ch0, ch1;\nstatic uint32_t state;\n\nstatic uint32_t readBtns() {\n uint32_t r = 0;\n\n updateScanCodes();\n\n KEY(A);\n KEY(B);\n KEY(LEFT);\n KEY(RIGHT);\n KEY(UP);\n KEY(DOWN);\n KEY(MENU);\n KEY(EXIT);\n KEY(RESET);\n\n KEY(A2);\n KEY(B2);\n KEY(LEFT2);\n KEY(RIGHT2);\n KEY(UP2);\n KEY(DOWN2);\n\n ch0 = readADC(0);\n ch1 = readADC(1);\n\n if (ch0 < MID - DEAD)\n SET(UP);\n if (ch0 > MID + DEAD)\n SET(DOWN);\n\n if (ch1 < MID - DEAD)\n SET(LEFT);\n if (ch1 > MID + DEAD)\n SET(RIGHT);\n\n return r;\n}\n\n//% expose\nint pressureLevelByButtonId(int btnId, int codalId) {\n int inv = 0;\n int v = 0;\n\n switch ((Key)btnId) {\n case Key::DOWN:\n v = ch0;\n inv = 1;\n break;\n case Key::UP:\n v = ch0;\n inv = -1;\n break;\n case Key::RIGHT:\n v = ch1;\n inv = 1;\n break;\n case Key::LEFT:\n v = ch1;\n inv = -1;\n break;\n default:\n break;\n }\n\n if (adcFD < 0 || inv == 0) {\n return (state & (1 << btnId)) ? 512 : 0;\n }\n\n int dead = DEAD / 4;\n\n v = (v - MID) * inv;\n v = (v - dead) * 512 / (MID - dead);\n\n if (v < 0)\n v = 0;\n if (v > 512)\n v = 512;\n\n return v;\n}\n\nstatic void *btnPoll(void *dummy) {\n (void)dummy;\n\n state = readBtns();\n int k = 0;\n while (1) {\n sleep_core_us(5000);\n uint32_t nstate = readBtns();\n\n if (k++ % 30 == 0) {\n // DMESG(\"CH0 %p CH1 %p\", readADC(0), readADC(1));\n }\n\n if (state != nstate) {\n for (int i = 1; i < 32; ++i) {\n uint32_t mask = 1 << i;\n int ev = 0;\n if ((state & mask) && !(nstate & mask))\n ev = INTERNAL_KEY_UP;\n else if (!(state & mask) && (nstate & mask)) {\n ev = INTERNAL_KEY_DOWN;\n if (i == (int)Key::EXIT)\n target_exit();\n else if (i == (int)Key::RESET)\n target_reset();\n }\n if (ev) {\n // DMESG(\"evt: %d at %d\", ev, i);\n raiseEvent(ev, i);\n raiseEvent(ev, 0); // any key\n }\n }\n state = nstate;\n }\n }\n\n return NULL;\n}\n\nvoid initKeys() {\n DMESG(\"init keys\");\n // music::playTone(0, 0); // start music process early\n\n sleep_core_us(200000); // make sure screen update starts to avoid race on config\n\n if (getConfigString(\"SCAN_CODES\")) {\n useScanCodes = 1;\n scanCodeFD = open(getConfigString(\"SCAN_CODES\"), O_RDONLY);\n if (scanCodeFD < 0) {\n DMESG(\"can't open %s\", getConfigString(\"SCAN_CODES\"));\n return;\n }\n } else {\n wiringPiSetupGpio();\n }\n\n pthread_t disp;\n pthread_create(&disp, NULL, btnPoll, NULL);\n pthread_detach(disp);\n}\n\n//% expose\nvoid setupButton(int buttonId, int key) {\n (void)buttonId;\n (void)key;\n // not needed on RPi\n}\n\n} // namespace pxt\n",
1763
- "pxt.json": "{\n \"name\": \"hw---rpi\",\n \"description\": \"Raspberry Pi\",\n \"dependencies\": {\n \"core---linux\": \"*\",\n \"mixer---linux\": \"*\",\n \"screen---linux\": \"*\",\n \"settings---files\": \"*\",\n \"controller---none\": \"*\",\n \"serial---linux\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"keys.cpp\",\n \"config.ts\",\n \"gamesel.cpp\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"Pi0\",\n \"description\": \"Raspberry Pi Zero (custom piCore Linux image)\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#pi0\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEUAAAD/k8T/9gn/gTX///8CbOdcAAAB3klEQVRo3u1aQW7EIAyMlBcg+QXNB1D8AiT//01lsONuKZUQzWGjethmhMdMsAu9dLd0Mx5iKIlKYzwBEWUy1iRHr4mI65saqRVslan0LoQUQ695vhuKFCyAABY3EDcSDNJ5p9m6zlALF11oBiQ287lmpE6jHyUT3qBvFHFDHdZPMHYiauCataoztL3Z+23hNRSqK3fa2LCVYz1MtlvEXnqIsMdfNYs/6WC/t2Hg7/i4Gf/WkG0ABx/nwWebg9cMmc/LUJk9dovhwWbIq4YHytTFYAzEeL2Hx4mnglsfEVvuIVArvPi9js1TwdubYedcN8XKDN4q58p7hg5+zZkAwyiDMzxgaMNUz6nPmR1qMhj5A0PPYZ4wZIx9z+BaHAJu4i/0nAmgR7ACaw+zl6lgz4G2jFqhc+Am7Hf3cuIMdudMjwx4cOXmDZFmhzqDYTS4cvMl4+1uyMrDKzffQ/5arL1fuXIO/1MFI+y2+gyvXKXlX2JcuUAgEAgEAoFAIBAIBAKBQOA7HvAf8F8VfMPDQfVHOmnCUIp/6ipKBVZF6pSoeqqUXNIpEsaGWEJ42lqSFiRCvCSSTrIp9AlDfFpxlJphpV7yKf1espAVIlfhMGxx74YmeMlIeNgXJ+42/ASw+1fGCliG7AAAAABJRU5ErkJggg==\"\n },\n \"compileServiceVariant\": \"rpi\",\n \"skipLocalization\": true\n}\n",
1763
+ "pxt.json": "{\n \"name\": \"hw---rpi\",\n \"description\": \"Raspberry Pi\",\n \"dependencies\": {\n \"core---linux\": \"*\",\n \"mixer---linux\": \"*\",\n \"screen---linux\": \"*\",\n \"settings---files\": \"*\",\n \"controller---none\": \"*\",\n \"serial---linux\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"keys.cpp\",\n \"config.ts\",\n \"gamesel.cpp\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"Pi0\",\n \"description\": \"Raspberry Pi Zero (custom piCore Linux image)\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#pi0\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEUAAAD/k8T/9gn/gTX///8CbOdcAAAB3klEQVRo3u1aQW7EIAyMlBcg+QXNB1D8AiT//01lsONuKZUQzWGjethmhMdMsAu9dLd0Mx5iKIlKYzwBEWUy1iRHr4mI65saqRVslan0LoQUQ695vhuKFCyAABY3EDcSDNJ5p9m6zlALF11oBiQ287lmpE6jHyUT3qBvFHFDHdZPMHYiauCataoztL3Z+23hNRSqK3fa2LCVYz1MtlvEXnqIsMdfNYs/6WC/t2Hg7/i4Gf/WkG0ABx/nwWebg9cMmc/LUJk9dovhwWbIq4YHytTFYAzEeL2Hx4mnglsfEVvuIVArvPi9js1TwdubYedcN8XKDN4q58p7hg5+zZkAwyiDMzxgaMNUz6nPmR1qMhj5A0PPYZ4wZIx9z+BaHAJu4i/0nAmgR7ACaw+zl6lgz4G2jFqhc+Am7Hf3cuIMdudMjwx4cOXmDZFmhzqDYTS4cvMl4+1uyMrDKzffQ/5arL1fuXIO/1MFI+y2+gyvXKXlX2JcuUAgEAgEAoFAIBAIBAKBQOA7HvAf8F8VfMPDQfVHOmnCUIp/6ipKBVZF6pSoeqqUXNIpEsaGWEJ42lqSFiRCvCSSTrIp9AlDfFpxlJphpV7yKf1espAVIlfhMGxx74YmeMlIeNgXJ+42/ASw+1fGCliG7AAAAABJRU5ErkJggg==\"\n },\n \"compileServiceVariant\": \"rpi\",\n \"skipLocalization\": true\n}\n",
1764
1764
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace control {\n\n /** Run specified user program. */\n //% shim=control::runProgram\n function runProgram(prog: string): void;\n\n /**\n * Deletes a user program\n */\n //% shim=control::deleteProgram\n function deleteProgram(prog: string): void;\n}\n\n// Auto-generated. Do not edit. Really.\n"
1765
1765
  },
1766
1766
  "hw---samd51": {
1767
1767
  "basepins.d.ts": "//% advanced=true\ndeclare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_LED)\n const LED: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SDA)\n const SDA: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCL)\n const SCL: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCK)\n const SCK: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MISO)\n const MISO: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MOSI)\n const MOSI: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_RX)\n const RX: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_TX)\n const TX: DigitalInOutPin;\n}\n",
1768
1768
  "config.ts": "namespace config {\n // all from bootloader\n}\n",
1769
1769
  "device.d.ts": "// \n",
1770
- "pxt.json": "{\n \"name\": \"hw---samd51\",\n \"description\": \"SAMD51 board\",\n \"dependencies\": {\n \"core---samd\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---samd\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"D5\",\n \"description\": \"Board based on Microchip ATSAMD51\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#d5\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEUAP6143FL/gTX///8AAACgtqsbAAABr0lEQVRo3u2WgY2DMAxFI2WCk24CsoDFnwCJ/Wc622lwUxpVgHWlNF+p9eOYRwiUEH6c1YEd+I/A31k1mZfeESBUk3nWVwB53fyAMwvIQJebMlVRdWKgXrAjUPWFQMfHZlYBTsCS6cArAu31NavcX7B+m5T5awPXG/10rk+RDuzADuzADnwF7OryEZmNIWA9HKFpNRFcbuYVkCjmrinGwDluxbCKMYGHJZZ2KxLYI5AybTFam41J+jKZ5dxkRTHUAiQdswm0mOrMecCAPATxVraeIRUjMqBdskZr0C7ZWtfAADH1TQldV1SEiByBGs8NRMAhYHQH0j4gQA0g9q0hhSaQvIFwAmIRPUkeAmK998RjQPIGwh1Ib59hBDHAcw1Jfl53GdCCqPYZkDYCKWolqW38U7YDI4cGkLYDNTaBYR8wtIC0A4iiZ8CwHSihXXgCIO7lAKzVgZ8HxE39a/30GpzVgXdKVW+sht4GTBjGkWNpQkk5I1GMRZYaLmgCxzQgDaMYbZCDknpwEg9DuctqA4VmR0Hml4EyQzwOVcDmJWu0xgcnzaclY6YUXOU53Kk/Y5YfN7mU0qQAAAAASUVORK5CYII=\"\n },\n \"compileServiceVariant\": \"samd51\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\",\n \"lightsensor\": \"file:../lightsensor\"\n },\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_WEBUSB\": 1\n }\n },\n \"skipLocalization\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---samd\"\n }\n}\n"
1770
+ "pxt.json": "{\n \"name\": \"hw---samd51\",\n \"description\": \"SAMD51 board\",\n \"dependencies\": {\n \"core---samd\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---samd\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"D5\",\n \"description\": \"Board based on Microchip ATSAMD51\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#d5\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEUAP6143FL/gTX///8AAACgtqsbAAABr0lEQVRo3u2WgY2DMAxFI2WCk24CsoDFnwCJ/Wc622lwUxpVgHWlNF+p9eOYRwiUEH6c1YEd+I/A31k1mZfeESBUk3nWVwB53fyAMwvIQJebMlVRdWKgXrAjUPWFQMfHZlYBTsCS6cArAu31NavcX7B+m5T5awPXG/10rk+RDuzADuzADnwF7OryEZmNIWA9HKFpNRFcbuYVkCjmrinGwDluxbCKMYGHJZZ2KxLYI5AybTFam41J+jKZ5dxkRTHUAiQdswm0mOrMecCAPATxVraeIRUjMqBdskZr0C7ZWtfAADH1TQldV1SEiByBGs8NRMAhYHQH0j4gQA0g9q0hhSaQvIFwAmIRPUkeAmK998RjQPIGwh1Ib59hBDHAcw1Jfl53GdCCqPYZkDYCKWolqW38U7YDI4cGkLYDNTaBYR8wtIC0A4iiZ8CwHSihXXgCIO7lAKzVgZ8HxE39a/30GpzVgXdKVW+sht4GTBjGkWNpQkk5I1GMRZYaLmgCxzQgDaMYbZCDknpwEg9DuctqA4VmR0Hml4EyQzwOVcDmJWu0xgcnzaclY6YUXOU53Kk/Y5YfN7mU0qQAAAAASUVORK5CYII=\"\n },\n \"compileServiceVariant\": \"samd51\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\",\n \"lightsensor\": \"file:../lightsensor\"\n },\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_WEBUSB\": 1\n }\n },\n \"skipLocalization\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---samd\"\n }\n}\n"
1771
1771
  },
1772
1772
  "hw---stm32f401": {
1773
1773
  "basepins.d.ts": "//% advanced=true\ndeclare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_LED)\n const LED: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SDA)\n const SDA: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCL)\n const SCL: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCK)\n const SCK: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MISO)\n const MISO: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MOSI)\n const MOSI: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_RX)\n const RX: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_TX)\n const TX: DigitalInOutPin;\n}\n",
1774
1774
  "config.ts": "namespace config {\n // all defined in bootloader\n}\n",
1775
1775
  "device.d.ts": "// \n",
1776
- "pxt.json": "{\n \"name\": \"hw---stm32f401\",\n \"description\": \"STM32F4 board\",\n \"dependencies\": {\n \"core---stm32\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---stm32\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"F4\",\n \"description\": \"Board based on STM32F4xx\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#f4\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEUAP62OLsT/gTX///8AAAAWHMbsAAABvklEQVRo3u2WDW7DIAyFkTjBpJ4gXMCKTxAp9z/TbEPcNJRtJdbKMj9R6xnMF35SteHDWA504C8Cb2vRovlyDohFi+b/C0gnaADUS5HsNFA3OzDwvuF1NQEKROHGwOU2MDC/gze7SxFnAlz2bnDgSpKNGwFVDuwFrqvVpdT5tYF0Ysd8rL8iDnSgAx3owO+ALpeN4G5jCFgPR+RuMdSoXGL8CRAgllQVI03l7mLKgw9PRhrmuLVcBAw7AiHT1EgtRQaoeIAXo89mSK6udoIIPJ1NIYsRp8oDCmQelhVSe75C2Ayp8B+3LHHXJIV86DUwoBi9FPm4rqiILDAEShwbiAFPAaM5EPqAzZuL2HeGEJpAsAaiERBV8KTzFBDr3554DgjWQDQHwttXGBEIYHmGwB+rW0aUglhsDYQXgRD1DMXW35QeYKTQAEIHkGMTGPqAoQWEDiBuegYMrwOb00UDAHGvTmBbDvx7QNwUXINrMpYDd0oP2VwNvQWYcJpnjqUxJeUejmI0ksRQQRM4pwnTNLORhjwpiSc742Eop6Q2UGg6C3l9GcgrxOOQAr/cssR7o8lJ+pP2qNGCq7yHnfoEQuYXTuqHoj8AAAAASUVORK5CYII=\"\n },\n \"compileServiceVariant\": \"stm32f401\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\",\n \"lightsensor\": \"file:../lightsensor\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_WEBUSB\": 1,\n \"PXT_DEFAULT_ACCELEROMETER\": \"ACCELEROMETER_TYPE_MMA8453\"\n }\n },\n \"dalDTS\": {\n \"corePackage\": \"../core---stm32\"\n }\n}\n"
1776
+ "pxt.json": "{\n \"name\": \"hw---stm32f401\",\n \"description\": \"STM32F4 board\",\n \"dependencies\": {\n \"core---stm32\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---stm32\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"F4\",\n \"description\": \"Board based on STM32F4xx\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#f4\",\n \"cardType\": \"hw\",\n \"imageUrl\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4BAMAAACHjORcAAAAD1BMVEUAP62OLsT/gTX///8AAAAWHMbsAAABvklEQVRo3u2WDW7DIAyFkTjBpJ4gXMCKTxAp9z/TbEPcNJRtJdbKMj9R6xnMF35SteHDWA504C8Cb2vRovlyDohFi+b/C0gnaADUS5HsNFA3OzDwvuF1NQEKROHGwOU2MDC/gze7SxFnAlz2bnDgSpKNGwFVDuwFrqvVpdT5tYF0Ysd8rL8iDnSgAx3owO+ALpeN4G5jCFgPR+RuMdSoXGL8CRAgllQVI03l7mLKgw9PRhrmuLVcBAw7AiHT1EgtRQaoeIAXo89mSK6udoIIPJ1NIYsRp8oDCmQelhVSe75C2Ayp8B+3LHHXJIV86DUwoBi9FPm4rqiILDAEShwbiAFPAaM5EPqAzZuL2HeGEJpAsAaiERBV8KTzFBDr3554DgjWQDQHwttXGBEIYHmGwB+rW0aUglhsDYQXgRD1DMXW35QeYKTQAEIHkGMTGPqAoQWEDiBuegYMrwOb00UDAHGvTmBbDvx7QNwUXINrMpYDd0oP2VwNvQWYcJpnjqUxJeUejmI0ksRQQRM4pwnTNLORhjwpiSc742Eop6Q2UGg6C3l9GcgrxOOQAr/cssR7o8lJ+pP2qNGCq7yHnfoEQuYXTuqHoj8AAAAASUVORK5CYII=\"\n },\n \"compileServiceVariant\": \"stm32f401\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\",\n \"lightsensor\": \"file:../lightsensor\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_WEBUSB\": 1,\n \"PXT_DEFAULT_ACCELEROMETER\": \"ACCELEROMETER_TYPE_MMA8453\"\n }\n },\n \"dalDTS\": {\n \"corePackage\": \"../core---stm32\"\n }\n}\n"
1777
1777
  },
1778
1778
  "hw---rp2040": {
1779
1779
  "basepins.d.ts": "//% advanced=true\ndeclare namespace pins {\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_LED)\n const LED: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SDA)\n const SDA: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCL)\n const SCL: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_SCK)\n const SCK: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MISO)\n const MISO: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_MOSI)\n const MOSI: DigitalInOutPin;\n\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_RX)\n const RX: DigitalInOutPin;\n //% fixedInstance shim=pxt::getPinCfg(CFG_PIN_TX)\n const TX: DigitalInOutPin;\n}\n",
1780
1780
  "config.ts": "namespace config {\n // in flash now\n}",
1781
1781
  "device.d.ts": "// nothing here yet",
1782
- "pxt.json": "{\n \"name\": \"hw---rp2040\",\n \"description\": \"RP2040 board\",\n \"dependencies\": {\n \"core---rp2040\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---rp2040\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"R2\",\n \"description\": \"Board based on Raspberry Pi RP2040\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#r2\",\n \"cardType\": \"hw\"\n },\n \"compileServiceVariant\": \"rp2040\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_WEBUSB\": 1\n }\n },\n \"experimentalHw\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---rp2040\"\n }\n}\n"
1782
+ "pxt.json": "{\n \"name\": \"hw---rp2040\",\n \"description\": \"RP2040 board\",\n \"dependencies\": {\n \"core---rp2040\": \"*\",\n \"screen---st7735\": \"*\",\n \"mixer---rp2040\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"config.ts\",\n \"basepins.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"R2\",\n \"description\": \"Board based on Raspberry Pi RP2040\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#r2\",\n \"cardType\": \"hw\"\n },\n \"compileServiceVariant\": \"rp2040\",\n \"cppDependencies\": {\n \"accelerometer\": \"file:../accelerometer\"\n },\n \"skipLocalization\": true,\n \"yotta\": {\n \"optionalConfig\": {\n \"DEVICE_JACDAC_DEBUG\": 1\n },\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_WEBUSB\": 1\n }\n },\n \"experimentalHw\": true,\n \"dalDTS\": {\n \"corePackage\": \"../core---rp2040\"\n }\n}\n"
1783
1783
  },
1784
1784
  "hw---vm": {
1785
1785
  "config.ts": "\nnamespace config {\n export const DISPLAY_WIDTH = 160;\n export const DISPLAY_HEIGHT = 120;\n}\n\ncontrol.internalOnEvent(INTERNAL_KEY_DOWN, 100, () => control.reset())\n",
1786
1786
  "device.d.ts": "declare namespace control {\n}",
1787
1787
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum Key {\n KEY_LEFT = 1,\n KEY_UP = 2,\n KEY_RIGHT = 3,\n KEY_DOWN = 4,\n KEY_A = 5,\n KEY_B = 6,\n KEY_MENU = 7,\n KEY_RESET = 100,\n KEY_EXIT = 101,\n }\n\n// Auto-generated. Do not edit. Really.\n",
1788
- "pxt.json": "{\n \"name\": \"hw---vm\",\n \"description\": \"VM\",\n \"dependencies\": {\n \"core---vm\": \"*\",\n \"mixer---ext\": \"*\",\n \"screen---ext\": \"*\",\n \"settings---files\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"sdlmain.cpp\",\n \"config.ts\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"VM\",\n \"description\": \"VM\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#vm\",\n \"cardType\": \"hw\"\n },\n \"compileServiceVariant\": \"vm\",\n \"skipLocalization\": true,\n \"experimentalHw\": true\n}\n",
1788
+ "pxt.json": "{\n \"name\": \"hw---vm\",\n \"description\": \"VM\",\n \"dependencies\": {\n \"core---vm\": \"*\",\n \"mixer---ext\": \"*\",\n \"screen---ext\": \"*\",\n \"settings---files\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"sdlmain.cpp\",\n \"config.ts\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"device.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"card\": {\n \"name\": \"VM\",\n \"description\": \"VM\",\n \"learnMoreUrl\": \"https://arcade.makecode.com/hardware#vm\",\n \"cardType\": \"hw\"\n },\n \"compileServiceVariant\": \"vm\",\n \"skipLocalization\": true,\n \"experimentalHw\": true\n}\n",
1789
1789
  "sdlmain.cpp": "#include \"SDL.h\"\n#include <stdint.h>\n#include <stdio.h>\n#include <ctype.h>\n\n#if UINTPTR_MAX == 0xffffffff\n#define BINSUFF \"-32\"\n#elif UINTPTR_MAX == 0xffffffffffffffff\n#define BINSUFF \"\"\n#else\n#error \"UINTPTR_MAX has invalid value\"\n#endif\n\n#if defined(__IPHONEOS__) || defined(__ANDROID__)\n#define PXT_STATIC 1\n#define PXT_TOUCH 1\n#define PXT_IOS 1\n#endif\n\n#if defined(__WINDOWS__)\n#include <windows.h>\n#define WIN_StringToUTF8(S) \\\n SDL_iconv_string(\"UTF-8\", \"UTF-16LE\", (char *)(S), (SDL_wcslen(S) + 1) * sizeof(WCHAR))\n#define WIN_UTF8ToString(S) \\\n (WCHAR *)SDL_iconv_string(\"UTF-16LE\", \"UTF-8\", (char *)(S), SDL_strlen(S) + 1)\n#endif\n\n#ifndef PXT_STATIC\n#if defined(__MACOSX__)\n#define SONAME \"libpxt\" BINSUFF \".dylib\"\n#elif defined(__WINDOWS__)\n#define SONAME \"pxt\" BINSUFF \".dll\"\n#else\n#define SONAME \"libpxt\" BINSUFF \".so\"\n#endif\n#endif\n\n#define WIDTH 160\n#define HEIGHT 120\n\nint win_width, win_height;\n\nSDL_Rect activeDisplayRect;\n\nSDL_Renderer *renderer;\n\nconst int SCREEN_WIDTH = WIDTH * 4;\nconst int SCREEN_HEIGHT = HEIGHT * 4;\n\nconst int INTERNAL_KEY_UP = 2050;\nconst int INTERNAL_KEY_DOWN = 2051;\n\nenum Key {\n KEY_LEFT = 1,\n KEY_UP,\n KEY_RIGHT,\n KEY_DOWN,\n KEY_A,\n KEY_B,\n KEY_MENU,\n KEY_RESET = 100, // passed as event to TS, which does control.reset()\n KEY_EXIT, // handled here\n};\n\nint mapKeyCode(int sdlCode) {\n switch (sdlCode) {\n case SDLK_ESCAPE:\n return KEY_EXIT;\n case '/':\n return KEY_RESET;\n case 'a':\n case SDLK_LEFT:\n return KEY_LEFT;\n case 'd':\n case SDLK_RIGHT:\n return KEY_RIGHT;\n case 'w':\n case SDLK_UP:\n return KEY_UP;\n case 's':\n case SDLK_DOWN:\n return KEY_DOWN;\n case ' ':\n case 'q':\n case 'z':\n return KEY_A;\n case 'x':\n case 'e':\n case SDLK_RETURN:\n return KEY_B;\n\n case 'm':\n return KEY_MENU;\n\n case 'j':\n return KEY_LEFT + 7;\n case 'i':\n return KEY_UP + 7;\n case 'l':\n return KEY_RIGHT + 7;\n case 'k':\n return KEY_DOWN + 7;\n case 'u':\n return KEY_A + 7;\n case 'o':\n return KEY_B + 7;\n\n default:\n return 0;\n }\n}\n\ntypedef void (*get_pixels_t)(int width, int height, uint32_t *screen);\ntypedef void (*raise_event_t)(int src, int val);\ntypedef void (*vm_start_t)(const char *fn);\ntypedef void (*vm_start_buffer_t)(uint8_t *data, unsigned len);\ntypedef int (*get_logs_t)(int logtype, char *dst, int maxSize);\ntypedef int (*get_panic_code_t)();\ntypedef void (*get_audio_samples_t)(int16_t *buf, unsigned numSamples);\n\n#ifdef PXT_STATIC\nextern \"C\" {\nvoid pxt_screen_get_pixels(int width, int height, uint32_t *screen);\nvoid pxt_raise_event(int src, int val);\nvoid pxt_vm_start(const char *fn);\nvoid pxt_vm_start_buffer(uint8_t *data, unsigned len);\nint pxt_get_logs(int logtype, char *dst, int maxSize);\nint pxt_get_panic_code();\nvoid pxt_get_audio_samples(int16_t *buf, unsigned numSamples);\n}\n#else\nget_audio_samples_t pxt_get_audio_samples;\nraise_event_t pxt_raise_event;\nvm_start_buffer_t pxt_vm_start_buffer;\n#endif\n\nint exitReq;\n\nvoid raise_key(Key k, int ev) {\n if (k == KEY_EXIT && ev == INTERNAL_KEY_UP)\n exitReq = 1;\n pxt_raise_event(ev, k);\n pxt_raise_event(ev, 0); // any\n}\n\nvoid fatal(const char *msg, const char *info = \"\") {\n SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, \"%s %s (SDL Error: %s)\", msg, info ? info : \"\",\n SDL_GetError());\n exit(1);\n}\n\n#ifndef PXT_TOUCH\nvoid init_touch_keys() {}\nvoid draw_touch_keys() {}\nvoid handle_touch_events(SDL_Event &) {}\n#else\nstruct OnScreenKey {\n Key keyId;\n SDL_Point center;\n char name;\n bool isPressed, prevPressed;\n};\n\nstruct TrackedFinger {\n SDL_FingerID fingerId;\n OnScreenKey *lastKey, *secondLastKey;\n};\n\n#define NUM_FINGERS 10\n#define NUM_KEYS 8\n\nOnScreenKey keys[NUM_KEYS];\nTrackedFinger fingers[NUM_FINGERS];\n\nint distance(SDL_Point &a, SDL_Point &b) {\n return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);\n}\n\nvoid add_key(Key kid, char name, int x, int y) {\n for (int i = 0; i < NUM_KEYS; ++i) {\n if (keys[i].keyId == 0) {\n auto k = &keys[i];\n k->keyId = kid;\n k->center.x = x;\n k->center.y = y;\n k->name = name;\n break;\n }\n }\n}\n\nvoid init_touch_keys() {\n int widthLeft = activeDisplayRect.x;\n int widthRight = win_width - activeDisplayRect.x - activeDisplayRect.w;\n\n int kps = widthLeft / 2 - 10;\n if (kps > win_height / 6)\n kps = win_height / 6;\n int kpx = widthLeft / 2;\n int menuY = win_height / 10;\n int kpy = win_height / 2 + menuY;\n\n add_key(KEY_MENU, 'M', kpx - kps, menuY);\n add_key(KEY_EXIT, 'E', kpx + kps, menuY);\n\n add_key(KEY_LEFT, '<', kpx - kps, kpy);\n add_key(KEY_RIGHT, '<', kpx + kps, kpy);\n add_key(KEY_UP, '^', kpx, kpy - kps);\n add_key(KEY_DOWN, 'v', kpx, kpy + kps);\n\n int abx = win_width - widthRight / 2;\n int ay = win_height / 2 - kps;\n int by = win_height / 2 + kps;\n\n add_key(KEY_A, 'A', abx, ay);\n add_key(KEY_B, 'B', abx, by);\n}\n\nvoid draw_touch_keys() {\n SDL_Rect keyR;\n int sz = 3;\n keyR.w = sz * 2;\n keyR.h = sz * 2;\n for (int i = 0; i < NUM_KEYS; ++i) {\n SDL_SetRenderDrawColor(renderer, 255, keys[i].isPressed ? 255 : 0, 0, 255);\n keyR.x = keys[i].center.x - sz;\n keyR.y = keys[i].center.y - sz;\n SDL_RenderFillRect(renderer, &keyR);\n }\n}\n\nvoid handle_touch_events(SDL_Event &e) {\n if (e.type == SDL_FINGERDOWN || e.type == SDL_FINGERUP || e.type == SDL_FINGERMOTION) {\n SDL_Point p;\n p.x = e.tfinger.x * win_width;\n p.y = e.tfinger.y * win_height;\n\n int i, firstFree = -1;\n for (i = 0; i < NUM_FINGERS; ++i) {\n if (fingers[i].lastKey) {\n if (fingers[i].fingerId == e.tfinger.fingerId)\n break;\n } else {\n if (firstFree == -1)\n firstFree = i;\n }\n }\n\n if (e.type == SDL_FINGERUP) {\n if (i != NUM_FINGERS)\n fingers[i].lastKey = NULL;\n } else {\n if (i == NUM_FINGERS) {\n i = firstFree;\n if (i == -1)\n fatal(\"too many fingers?\");\n }\n fingers[i].fingerId = e.tfinger.fingerId;\n auto nearest = &keys[0];\n auto nearestDistance = -1;\n for (int j = 0; j < NUM_KEYS; ++j) {\n auto dist = distance(p, keys[j].center);\n if (nearestDistance == -1 || nearestDistance > dist) {\n nearestDistance = dist;\n nearest = &keys[j];\n }\n }\n\n fingers[i].secondLastKey = NULL;\n auto minDistance = (win_height / 5) * (win_height / 5);\n if (nearestDistance > minDistance)\n nearest = NULL;\n else {\n auto secondNearest = &keys[0];\n auto secondNearestDist = -1;\n for (int j = 0; j < NUM_KEYS; ++j) {\n if (&keys[j] == nearest)\n continue;\n auto dist = distance(p, keys[j].center);\n if (secondNearestDist == -1 || secondNearestDist > dist) {\n secondNearestDist = dist;\n secondNearest = &keys[j];\n }\n }\n\n auto maxDist = nearestDistance * 16 / 10;\n if (secondNearestDist < maxDist) {\n fingers[i].secondLastKey = secondNearest;\n }\n }\n\n fingers[i].lastKey = nearest;\n }\n\n for (int j = 0; j < NUM_KEYS; ++j) {\n keys[j].prevPressed = keys[j].isPressed;\n keys[j].isPressed = false;\n }\n\n for (int i = 0; i < NUM_FINGERS; ++i) {\n if (fingers[i].lastKey)\n fingers[i].lastKey->isPressed = true;\n if (fingers[i].secondLastKey)\n fingers[i].secondLastKey->isPressed = true;\n }\n\n for (int j = 0; j < NUM_KEYS; ++j) {\n if (keys[j].prevPressed != keys[j].isPressed)\n raise_key(keys[j].keyId, keys[j].isPressed ? INTERNAL_KEY_DOWN : INTERNAL_KEY_UP);\n }\n }\n}\n#endif\n\n#define SDL_CHECK(call) \\\n if (!(call)) { \\\n fatal(\"SDL Call error\", #call); \\\n }\n\n#ifndef PXT_STATIC\nvoid *loadPXTLib(char *argv[]) {\n const char *exename = argv[0];\n if (exename == NULL || !strchr(exename, '/'))\n exename = \"./vm\";\n int solen = strlen(exename) + strlen(SONAME);\n char namebuf[solen + 1];\n strcpy(namebuf, exename);\n strcpy(strrchr(namebuf, '/') + 1, SONAME);\n\n void *vmDLL = SDL_LoadObject(namebuf);\n if (!vmDLL) {\n fatal(\"can't load DLL\", namebuf);\n }\n\n return vmDLL;\n}\n#endif\n\nchar logtmp[64 * 1024];\n\nvoid flush_logs(get_logs_t get_logs) {\n while (1) {\n int sz = get_logs(0, logtmp, sizeof(logtmp) - 1);\n if (sz <= 0)\n break;\n for (int i = 0; i < sz;) {\n int j;\n for (j = i; j < sz; ++j) {\n if (logtmp[j] == '\\n') {\n break;\n }\n }\n logtmp[j] = 0;\n SDL_Log(\"%s\", logtmp + i);\n i = j + 1;\n }\n }\n}\n\nvoid audioCallback(void *userdata, Uint8 *stream, int len) {\n pxt_get_audio_samples((int16_t *)stream, len / 2);\n}\n\nSDL_AudioDeviceID audioDev;\nvoid openAudio() {\n SDL_AudioSpec wanted, actual;\n\n SDL_zero(wanted);\n SDL_zero(actual);\n wanted.freq = 44100;\n wanted.format = AUDIO_S16SYS;\n wanted.channels = 1;\n wanted.samples = 1024;\n wanted.callback = audioCallback;\n\n int n = SDL_GetNumAudioDevices(0);\n for (int i = 0; i < n; ++i) {\n SDL_Log(\"audio %d %s\", i, SDL_GetAudioDeviceName(i, 0));\n }\n\n audioDev = SDL_OpenAudioDevice(NULL, 0, &wanted, &actual, 0);\n\n // SDL_CHECK(SDL_OpenAudio(&wanted, &actual) == 0);\n\n SDL_Log(\"audio device %d Hz, %d ch, %d sampl\", actual.freq, actual.channels, actual.samples);\n}\n\nstatic void SDLCALL logOutput(void *userdata, int category, SDL_LogPriority priority,\n const char *message) {\n (void)userdata;\n\n#if defined(__WINDOWS__)\n static HANDLE stdoutHandle;\n\n if (!stdoutHandle) {\n AttachConsole(ATTACH_PARENT_PROCESS);\n stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);\n }\n\n unsigned len = strlen(message) + 2;\n char msgNL[len + 1];\n strcpy(msgNL, message);\n strcat(msgNL, \"\\r\\n\");\n\n OutputDebugString(msgNL);\n\n unsigned long charsWritten;\n WriteFile(stdoutHandle, msgNL, len, &charsWritten, NULL);\n#else\n fprintf(stderr, \"%s\\n\", message);\n#endif\n}\n\n#ifdef PXT_IOS\nextern \"C\" void fetchSources(const char *scriptId);\nextern \"C\" void initCache();\n#endif\n\nextern \"C\" int main(int argc, char *argv[]) {\n#ifdef PXT_IOS\n initCache();\n#endif\n\n SDL_LogSetAllPriority(SDL_LOG_PRIORITY_INFO);\n\n SDL_LogSetOutputFunction(logOutput, NULL);\n\n#ifndef PXT_STATIC\n SDL_Log(\"loading %s ...\", SONAME);\n\n void *vmDLL = loadPXTLib(argv);\n get_pixels_t pxt_screen_get_pixels =\n (get_pixels_t)SDL_LoadFunction(vmDLL, \"pxt_screen_get_pixels\");\n vm_start_t pxt_vm_start = (vm_start_t)SDL_LoadFunction(vmDLL, \"pxt_vm_start\");\n pxt_vm_start_buffer = (vm_start_buffer_t)SDL_LoadFunction(vmDLL, \"pxt_vm_start_buffer\");\n pxt_raise_event = (raise_event_t)SDL_LoadFunction(vmDLL, \"pxt_raise_event\");\n get_logs_t pxt_get_logs = (get_logs_t)SDL_LoadFunction(vmDLL, \"pxt_get_logs\");\n get_panic_code_t pxt_get_panic_code =\n (get_panic_code_t)SDL_LoadFunction(vmDLL, \"pxt_get_panic_code\");\n pxt_get_audio_samples = (get_audio_samples_t)SDL_LoadFunction(vmDLL, \"pxt_get_audio_samples\");\n\n if (!pxt_screen_get_pixels || !pxt_vm_start || !pxt_vm_start_buffer || !pxt_raise_event ||\n !pxt_get_logs || !pxt_get_panic_code || !pxt_get_audio_samples) {\n fatal(\"can't load pxt function from DLL\", \"\");\n }\n#endif\n\n SDL_CHECK(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) >= 0);\n\n SDL_Window *window =\n SDL_CreateWindow(\"MakeCode Arcade64\", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,\n SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);\n\n SDL_GetWindowSize(window, &win_width, &win_height);\n\n SDL_CHECK(window != NULL);\n\n renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);\n\n SDL_Surface *surf;\n surf = SDL_CreateRGBSurfaceWithFormat(0, WIDTH, HEIGHT, 32, SDL_PIXELFORMAT_BGRA32);\n\n SDL_CHECK(surf != NULL);\n\n openAudio();\n\n memset(surf->pixels, 0, HEIGHT * WIDTH * 4);\n\n SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, surf);\n\n int ww2 = win_height * 4 / 3;\n int freeSpace = win_width - ww2;\n int widthLeft = 3 * freeSpace / 4;\n activeDisplayRect.x = widthLeft;\n activeDisplayRect.y = 0;\n activeDisplayRect.h = win_height;\n activeDisplayRect.w = ww2;\n\n init_touch_keys();\n\n SDL_RenderClear(renderer);\n SDL_RenderCopy(renderer, tex, NULL, &activeDisplayRect);\n SDL_RenderPresent(renderer);\n\n int now = SDL_GetTicks();\n int nextLoad = now + 100;\n int lastLoad = 0;\n\n SDL_Event e;\n int quit = 0;\n int numFr = 0;\n int prevTicks = SDL_GetTicks();\n\n const char *imageName = argv[1];\n#ifdef PXT_IOS\n const char *imageID = NULL;\n imageName = \"menu.pxt64\";\n#endif\n\n while (!quit) {\n now = SDL_GetTicks();\n\n if (nextLoad && now >= nextLoad) {\n#ifdef PXT_IOS\n if (imageID) {\n fetchSources(imageID);\n imageID = NULL;\n } else\n#endif\n pxt_vm_start(imageName);\n SDL_PauseAudioDevice(audioDev, 0);\n // SDL_PauseAudio(0);\n nextLoad = 0;\n lastLoad = now;\n }\n\n while (SDL_PollEvent(&e)) {\n if (e.type == SDL_QUIT) {\n quit = 1;\n }\n if ((e.type == SDL_KEYDOWN || e.type == SDL_KEYUP) && !e.key.repeat) {\n int ev = e.type == SDL_KEYDOWN ? INTERNAL_KEY_DOWN : INTERNAL_KEY_UP;\n auto kk = (Key)mapKeyCode(e.key.keysym.sym);\n if (kk == KEY_EXIT) {\n quit = 1;\n break;\n }\n if (kk)\n raise_key(kk, ev);\n }\n#ifdef PXT_IOS\n if (e.type == SDL_DROPFILE) {\n char *p = e.drop.file;\n while (*p && *p != ':')\n p++;\n while (*p && (*p == ':' || *p == '/'))\n p++;\n char *beg = p;\n if (*p == '_') {\n p++;\n while (isalnum(*p))\n p++;\n } else if (isdigit(*p)) {\n while (isdigit(*p) || *p == '-')\n p++;\n }\n if (p - beg > 8) {\n *p = 0;\n nextLoad = now + 300;\n SDL_free((void *)imageID);\n imageID = SDL_strdup(beg);\n }\n SDL_free(e.drop.file);\n }\n#endif\n\n if (e.type == SDL_MOUSEBUTTONDOWN) {\n // quit = 1;\n }\n handle_touch_events(e);\n }\n\n pxt_screen_get_pixels(WIDTH, HEIGHT, (uint32_t *)surf->pixels);\n\n SDL_UpdateTexture(tex, NULL, surf->pixels, WIDTH * 4);\n\n SDL_SetRenderDrawColor(renderer, 40, 40, 40, 255);\n SDL_RenderClear(renderer);\n SDL_RenderCopy(renderer, tex, NULL, &activeDisplayRect);\n\n draw_touch_keys();\n SDL_RenderPresent(renderer);\n\n flush_logs(pxt_get_logs);\n\n if (exitReq) {\n if (!nextLoad && now > 2000 + lastLoad) {\n SDL_Log(\"exit at key request\");\n nextLoad = now;\n }\n exitReq = 0;\n }\n\n if (!nextLoad) {\n int code = pxt_get_panic_code();\n if (code == -1) {\n // restart done in user code\n } else if (code >= 1000) {\n SDL_Log(\"hit soft crash, code=%d; restarting\", code - 1000);\n nextLoad = now + 3000;\n } else if (code != 0) {\n SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, \"fatal runtime error %d; bye\", code);\n exit(1);\n }\n }\n\n numFr++;\n int now = SDL_GetTicks();\n if (now - prevTicks > 1000) {\n // printf(\"fps=%d\\n\", numFr);\n prevTicks = now;\n numFr = 0;\n }\n\n#ifdef PXT_IOS\n SDL_Delay(25);\n#endif\n }\n\n SDL_DestroyWindow(window);\n SDL_Quit();\n\n return 0;\n}\n",
1790
1790
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace control {\n\n /** Run specified user program. */\n //% shim=control::runProgram\n function runProgram(prog: string): void;\n}\n\n// Auto-generated. Do not edit. Really.\n"
1791
1791
  },
@@ -1793,7 +1793,7 @@ var pxtTargetBundle = {
1793
1793
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum KeyboardKeyEvent {\n //% block=\"press\"\n Press = 0,\n //% block=\"up\"\n Up = 1,\n //% block=\"down\"\n Down = 2,\n }\n\n// Auto-generated. Do not edit. Really.\n",
1794
1794
  "keyboard.cpp": "// https://github.com/lancaster-university/codal-core/blob/master/source/drivers/HIDKeyboard.cpp\n\n#include \"pxt.h\"\n#include \"USB_HID_Keys.h\"\n\nenum class KeyboardKeyEvent {\n //% block=\"press\"\n Press,\n //% block=\"up\"\n Up,\n //% block=\"down\"\n Down\n};\n\nnamespace keyboard {\n //%\n void __flush() {\n pxt::keyboard.flush();\n }\n\n //% \n void __type(String text) {\n if (NULL != text)\n pxt::keyboard.type(text->getUTF8Data(), text->getUTF8Size());\n }\n\n //%\n void __key(uint16_t ckey, KeyboardKeyEvent event) {\n switch(event) {\n case KeyboardKeyEvent::Down:\n pxt::keyboard.keyDown(ckey);\n break;\n case KeyboardKeyEvent::Up:\n pxt::keyboard.keyUp(ckey);\n break;\n case KeyboardKeyEvent::Press:\n pxt::keyboard.press(ckey);\n break;\n }\n }\n\n //%\n void __mediaKey(uint16_t key, KeyboardKeyEvent event) {\n codal::MediaKey ckey = (codal::MediaKey)((int)codal::MediaKey::Mute + (int)key);\n switch(event) {\n case KeyboardKeyEvent::Down:\n pxt::keyboard.keyDown(ckey);\n break;\n case KeyboardKeyEvent::Up:\n pxt::keyboard.keyUp(ckey);\n break;\n case KeyboardKeyEvent::Press:\n pxt::keyboard.press(ckey);\n break;\n }\n }\n\n //%\n void __functionKey(uint16_t key, KeyboardKeyEvent event) {\n codal::FunctionKey ckey = (codal::FunctionKey)key;\n switch(event) {\n case KeyboardKeyEvent::Down:\n pxt::keyboard.keyDown(ckey);\n break;\n case KeyboardKeyEvent::Up:\n pxt::keyboard.keyUp(ckey);\n break;\n case KeyboardKeyEvent::Press:\n pxt::keyboard.press(ckey);\n break;\n }\n }\n\n //%\n void __modifierKey(uint16_t modifier, KeyboardKeyEvent event) {\n const Key key = { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | (uint8_t)modifier };\n // send keys\n switch(event) {\n case KeyboardKeyEvent::Down:\n pxt::keyboard.keyDown(key);\n break;\n case KeyboardKeyEvent::Up:\n pxt::keyboard.keyUp(key);\n break;\n case KeyboardKeyEvent::Press:\n pxt::keyboard.press(key);\n break;\n };\n }\n}",
1795
1795
  "keyboard.ts": "\nconst enum KeyboardMediaKey\n{\n //% block=\"mute\"\n Mute,\n //% block=\"volume up\"\n VolumeUp,\n //% block=\"volume down\"\n VolumeDown,\n //% block=\"play pause\"\n PlayPause,\n //% block=\"stop\"\n Stop,\n //% block=\"previous track\"\n PreviousTrack,\n //% block=\"next track\"\n NextTrack,\n //% block=\"mail\"\n Mail,\n //% block=\"calculator\"\n Calculator,\n //% block=\"web search\"\n WebSearch,\n //% block=\"web home\"\n WebHome,\n //% block=\"web favourites\"\n WebFavourites,\n //% block=\"web refresh\"\n WebRefresh,\n //% block=\"web stop\"\n WebStop,\n //% block=\"web forward\"\n WebForward,\n //% block=\"web back\"\n WebBack\n}\n\nconst enum KeyboardFunctionKey\n{\n //% block=\"F1\"\n F1Key = DAL.KEY_F1, \n //% block=\"F2\"\n F2Key = DAL.KEY_F2,\n //% block=\"F3\"\n F3Key = DAL.KEY_F3,\n //% block=\"F4\"\n F4Key = DAL.KEY_F4, \n //% block=\"F5\"\n F5Key = DAL.KEY_F5,\n //% block=\"F6\"\n F6Key = DAL.KEY_F6,\n //% block=\"F7\"\n F7Key = DAL.KEY_F7,\n //% block=\"F8\"\n F8Key = DAL.KEY_F8,\n //% block=\"F9\"\n F9Key = DAL.KEY_F9,\n //% block=\"F0\"\n F10Key = DAL.KEY_F10,\n //% block=\"F11\"\n F11Key = DAL.KEY_F11,\n //% block=\"F12\"\n F12Key = DAL.KEY_F12,\n //% block=\"F13\"\n F13Key = DAL.KEY_F13,\n //% block=\"F14\"\n F14Key = DAL.KEY_F14,\n //% block=\"F15\"\n F15Key = DAL.KEY_F15,\n //% block=\"F16\"\n F16Key = DAL.KEY_F16,\n //% block=\"F17\"\n F17Key = DAL.KEY_F17,\n //% block=\"F18\"\n F18Key = DAL.KEY_F18,\n //% block=\"F19\"\n F19Key = DAL.KEY_F19,\n //% block=\"F20\"\n F20Key = DAL.KEY_F20,\n //% block=\"F21\"\n F21Key = DAL.KEY_F21,\n //% block=\"F22\"\n F22Key = DAL.KEY_F22,\n //% block=\"F23\"\n F23Key = DAL.KEY_F23,\n //% block=\"F24\"\n F24Key = DAL.KEY_F24,\n\n //% block=\"enter\"\n Enter = DAL.KEY_ENTER,\n //% block=\"esc\"\n Esc = DAL.KEY_ESC,\n //% block=\"backspace\"\n Backspace = DAL.KEY_BACKSPACE,\n //% block=\"tab\"\n Tab = DAL.KEY_TAB,\n //% block=\"caps lock\"\n CapsLock = DAL.KEY_CAPSLOCK,\n //% block=\"num lock\"\n NumLock = DAL.KEY_NUMLOCK,\n //% block=\"keypad /\"\n KeypadSlash = DAL.KEY_KPSLASH,\n //% block=\"keypad *\"\n KeypadAsterisk = DAL.KEY_KPASTERISK,\n //% block=\"keypad -\"\n KeypadMinus = DAL.KEY_KPMINUS,\n //% block=\"keypad +\"\n KeypadPlus = DAL.KEY_KPPLUS,\n //% block=\"keypad enter\"\n KeypadEnter = DAL.KEY_KPENTER,\n //% block=\"keypad 1\"\n Keypad1 = DAL.KEY_KP1,\n //% block=\"keypad 2\"\n Keypad2 = DAL.KEY_KP2,\n //% block=\"keypad 3\"\n Keypad3 = DAL.KEY_KP3,\n //% block=\"keypad 4\"\n Keypad4 = DAL.KEY_KP4,\n //% block=\"keypad 5\"\n Keypad5 = DAL.KEY_KP5,\n //% block=\"keypad 6\"\n Keypad6 = DAL.KEY_KP6,\n //% block=\"keypad 7\"\n Keypad7 = DAL.KEY_KP7,\n //% block=\"keypad 8\"\n Keypad8 = DAL.KEY_KP8,\n //% block=\"keypad 9\"\n Keypad9 = DAL.KEY_KP9,\n //% block=\"keypad 0\"\n Keypad0 = DAL.KEY_KP0,\n //% block=\"keypad .\"\n KeypadDot = DAL.KEY_KPDOT,\n //% block=\"compose\"\n Compose = DAL.KEY_COMPOSE,\n //% block=\"power\"\n Power = DAL.KEY_POWER,\n //% block=\"=\"\n KeypadEqual = DAL.KEY_KPEQUAL,\n //% block=\"open\"\n Open = DAL.KEY_OPEN,\n //% block=\"help\"\n Help = DAL.KEY_HELP,\n //% block=\"props\"\n Props = DAL.KEY_PROPS,\n //% block=\"front\"\n Front = DAL.KEY_FRONT,\n //% block=\"stop\"\n Stop = DAL.KEY_STOP,\n //% block=\"again\"\n Again = DAL.KEY_AGAIN,\n //% block=\"undo\"\n Undo = DAL.KEY_UNDO,\n //% block=\"cut\"\n Cut = DAL.KEY_CUT,\n //% block=\"copy\"\n Copy = DAL.KEY_COPY,\n //% block=\"paste\"\n Paste = DAL.KEY_PASTE,\n //% block=\"find\"\n Find = DAL.KEY_FIND,\n //% block=\"mute\"\n Mute = DAL.KEY_MUTE,\n //% block=\"volume up\"\n VolumeUp = DAL.KEY_VOLUMEUP,\n //% block=\"volume down\"\n VolumeDown = DAL.KEY_VOLUMEDOWN,\n //% block=\"keypad ,\"\n KeypadComma = DAL.KEY_KPCOMMA,\n //% block=\"keypad jump comma\"\n KeypadJumpComma = DAL.KEY_KPJPCOMMA,\n //% block=\"keypad (\"\n KeypadLeftParenthesis = DAL.KEY_KPLEFTPAREN,\n //% block=\"keypad )\"\n KeypadRightParenthesis = DAL.KEY_KPRIGHTPAREN,\n\n //% block=\"print screen\"\n PrintScreen = DAL.KEY_SYSRQ,\n //% block=\"scroll lock\"\n ScrollLock = DAL.KEY_SCROLLLOCK,\n //% block=\"pause\"\n Pause = DAL.KEY_PAUSE,\n //% block=\"insert\"\n Insert = DAL.KEY_INSERT,\n //% block=\"home\"\n Home = DAL.KEY_HOME,\n //% block=\"page up\"\n PageUp = DAL.KEY_PAGEUP,\n //% block=\"delete\"\n DeleteForward = DAL.KEY_DELETE,\n //% block=\"end\"\n End = DAL.KEY_END,\n //% block=\"page down\"\n PageDown = DAL.KEY_PAGEDOWN,\n\n //% block=\"right arrow\"\n RightArrow = DAL.KEY_RIGHT,\n //% block=\"left arrow\"\n LeftArrow = DAL.KEY_LEFT,\n //% block=\"down arrow\"\n DownArrow = DAL.KEY_DOWN,\n //% block=\"up arrow\"\n UpArrow = DAL.KEY_UP\n}\n\nconst enum KeyboardModifierKey {\n //% block=\"Ctrl\"\n Control = DAL.KEY_MOD_LCTRL,\n //% block=\"Shift\"\n Shift = DAL.KEY_MOD_LSHIFT,\n //% block=\"Alt\"\n Alt = DAL.KEY_MOD_LALT,\n //% block=\"Command\"\n Meta = DAL.KEY_MOD_LMETA,\n //% block=\"Ctrl+Shift\"\n ControlShift = Control | Shift,\n //% block=\"Ctrl+Alt\"\n ControlAlt = Control | Alt,\n //% block=\"Shift+Alt\"\n ShiftAlt = Shift | Alt,\n //% block=\"Ctrl+Cmd\"\n ControlCommand = Control | Meta,\n //% block=\"Ctrl+Cmd\"\n ShiftCommand = Shift | Meta,\n //% block=\"Alt+Cmd\"\n AltCommand = Alt | Meta,\n //% block=\"Ctrl+Shift+Alt\"\n ControlShiftAlt = Control | Shift | Alt,\n //% block=\"Ctrl+Cmd+Shift+Alt\"\n ControlCommandShiftAlt = Control | Meta | Shift | Alt,\n //% block=\"Right Ctrl\"\n RightControl = DAL.KEY_MOD_RCTRL,\n //% block=\"Right Shift\"\n RightShift = DAL.KEY_MOD_RSHIFT,\n //% block=\"Right Alt\"\n RightAlt = DAL.KEY_MOD_RALT,\n //% block=\"Right Command\"\n RightMeta = DAL.KEY_MOD_RMETA\n}\n\n/**\n * Keyboard emulation\n */\n//% icon=\"\\uf11c\" color=\"#303030\"\nnamespace keyboard {\n /**\n * Send a sequence of keystrokes to the keyboard\n */\n //% blockId=keyboardType block=\"keyboard type $text||with $modifiers\"\n //% blockGap=8 weight=100\n //% text.shadowOptions.toString=true\n //% help=keyboard/type\n //% weight=100\n export function type(text: string, modifiers?: KeyboardModifierKey) {\n if (modifiers)\n __modifierKey(modifiers, KeyboardKeyEvent.Down);\n __type(text);\n __flush();\n }\n\n /**\n * Send a key command\n */\n //% blockId=keyboardStandardKey block=\"keyboard key %key|%event\"\n //% blockGap=8 weight=99\n //% help=keyboard/key\n export function key(key: string, event: KeyboardKeyEvent) {\n if (!key) return;\n const c = key.charCodeAt(0);\n __key(c, event);\n }\n\n /**\n * Send a media key command\n */\n //% blockId=keyboardMediaKey block=\"keyboard media %key|%event\"\n //% blockGap=8\n //% help=keyboard/media-key\n export function mediaKey(key: KeyboardMediaKey, event: KeyboardKeyEvent) {\n __mediaKey(key, event);\n }\n\n /**\n * Send a function key command\n */\n //% blockId=keyboardFunctionKey block=\"keyboard function %key|%event\"\n //% blockGap=8\n //% help=keyboard/function-key\n export function functionKey(key: KeyboardFunctionKey, event: KeyboardKeyEvent) {\n __functionKey(key, event)\n }\n\n /**\n * Send a modifier key command\n */\n //% blockId=keyboardModiferKey block=\"keyboard modifier %key|%event\"\n //% blockGap=8\n //% help=keyboard/modifier-key\n export function modifierKey(key: KeyboardModifierKey, event: KeyboardKeyEvent) {\n __modifierKey(key, event)\n }\n\n /**\n * Send up commands for any remaning down keys\n */\n //% blockId=keyboardClear block=\"keyboard clear all\"\n //% blockGap=8\n //% help=keyboard/clear-all-keys\n //% weight=10\n export function clearAllKeys() {\n __flush()\n }\n}",
1796
- "pxt.json": "{\n \"name\": \"keyboard\",\n \"description\": \"Keyboard emulation over HID\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"keyboard.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"keyboard.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"tests\": [\n \"test.ts\"\n ],\n \"yotta\": {\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_KEYBOARD\": 1\n }\n },\n \"icon\": \"/static/libs/keyboard.png\"\n}\n",
1796
+ "pxt.json": "{\n \"name\": \"keyboard\",\n \"description\": \"Keyboard emulation over HID\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"keyboard.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"keyboard.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"tests\": [\n \"test.ts\"\n ],\n \"yotta\": {\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_KEYBOARD\": 1\n }\n },\n \"icon\": \"/static/libs/keyboard.png\"\n}\n",
1797
1797
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace keyboard {\n //% shim=keyboard::__flush hidden=1\n function __flush(): void;\n\n //% shim=keyboard::__type hidden=1\n function __type(text: string): void;\n\n //% shim=keyboard::__key hidden=1\n function __key(ckey: number, event: KeyboardKeyEvent): void;\n\n //% shim=keyboard::__mediaKey hidden=1\n function __mediaKey(key: uint16, event: KeyboardKeyEvent): void;\n\n //% shim=keyboard::__functionKey hidden=1\n function __functionKey(key: uint16, event: KeyboardKeyEvent): void;\n\n //% shim=keyboard::__modifierKey hidden=1\n function __modifierKey(modifier: uint16, event: KeyboardKeyEvent): void;\n}\n\n// Auto-generated. Do not edit. Really.\n"
1798
1798
  },
1799
1799
  "light": {
@@ -1807,7 +1807,7 @@ var pxtTargetBundle = {
1807
1807
  "neopixeloverrides.ts": "//% weight=97\nnamespace light {\n\n}",
1808
1808
  "ns.ts": "\n/**\n * Functions to operate colored LEDs.\n */\n//% weight=100 color=\"#0078d7\" icon=\"\\uf00a\"\nnamespace light {\n\n}",
1809
1809
  "onboardstrip.ts": "namespace light {\n let _onboardStrip: light.LightStrip;\n /**\n * Get the onboard light strip.\n */\n //% help=light/onboard-strip\n //% blockId=\"neopixel_onboard_strip\" block=\"onboard strip\"\n //% weight=111 blockGap=8\n //% advanced=true\n export function onboardStrip(): NeoPixelStrip {\n if (_onboardStrip) return _onboardStrip;\n\n { // try onboard cfg\n const data = pins.pinByCfg(DAL.CFG_PIN_ONBOARD_DOTSTAR_DATA);\n const clk = pins.pinByCfg(DAL.CFG_PIN_ONBOARD_DOTSTAR_CLOCK);\n const dsnum = control.getConfigValue(DAL.CFG_NUM_ONBOARD_DOTSTARS, 0);\n const neo = pins.pinByCfg(DAL.CFG_PIN_ONBOARD_NEOPIXEL);\n const neonum = control.getConfigValue(DAL.CFG_NUM_ONBOARD_NEOPIXELS, 0);\n if (data && clk && dsnum > 0) {\n _onboardStrip = light.createAPA102Strip(data, clk, dsnum);\n _onboardStrip.setBrightness(96);\n return _onboardStrip;\n } else if (neo && neonum > 0) {\n _onboardStrip = light.createNeoPixelStrip(neo, neonum, NeoPixelMode.RGB);\n return _onboardStrip;\n }\n }\n\n { // resolve from pins\n const data = pins.pinByCfg(DAL.CFG_PIN_DOTSTAR_DATA);\n const clk = pins.pinByCfg(DAL.CFG_PIN_DOTSTAR_CLOCK);\n const dsnum = control.getConfigValue(DAL.CFG_NUM_DOTSTARS, 0);\n const neo = pins.pinByCfg(DAL.CFG_PIN_NEOPIXEL);\n const neonum = control.getConfigValue(DAL.CFG_NUM_NEOPIXELS, 0);\n if (data && clk && dsnum > 0) {\n _onboardStrip = light.createAPA102Strip(data, clk, dsnum);\n _onboardStrip.setBrightness(96);\n return _onboardStrip;\n } else if (neo && neonum > 0) {\n _onboardStrip = light.createNeoPixelStrip(neo, neonum, NeoPixelMode.RGB);\n return _onboardStrip;\n } else {\n _onboardStrip = light.createNeoPixelStrip(undefined, 0);\n }\n }\n\n return _onboardStrip;\n }\n}",
1810
- "pxt.json": "{\n \"name\": \"light\",\n \"description\": \"The programmable LED (WS2812b,APA102) driver.\",\n \"dependencies\": {\n \"core\": \"*\",\n \"color\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"neopixel.ts\",\n \"transitions.ts\",\n \"create.ts\",\n \"defaultstrip.ts\",\n \"onboardstrip.ts\",\n \"defaultlights.ts\",\n \"defaultlightsoverrides.ts\",\n \"ns.ts\",\n \"neopixeloverrides.ts\",\n \"animations.jres\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/light.png\"\n}\n",
1810
+ "pxt.json": "{\n \"name\": \"light\",\n \"description\": \"The programmable LED (WS2812b,APA102) driver.\",\n \"dependencies\": {\n \"core\": \"*\",\n \"color\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"neopixel.ts\",\n \"transitions.ts\",\n \"create.ts\",\n \"defaultstrip.ts\",\n \"onboardstrip.ts\",\n \"defaultlights.ts\",\n \"defaultlightsoverrides.ts\",\n \"ns.ts\",\n \"neopixeloverrides.ts\",\n \"animations.jres\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/light.png\"\n}\n",
1811
1811
  "targetoverrides.ts": "// define built-in strips here",
1812
1812
  "test.ts": "\nlet strip = light.createStrip()\nstrip.setBrightness(20)\n\nfunction flash(n: number) {\n control.runInParallel(() => {\n strip.setPixelColor(n, 0x0000ff)\n pause(1000)\n strip.setPixelColor(n, 0x000000)\n })\n}\n\nflash(0)\n\n",
1813
1813
  "transitions.ts": "namespace easing {\n export function linear(t: number): number { return t; }\n export function inQuad(t: number): number { return t * t; }\n export function outQuad(t: number): number { return t * (2 - t); }\n export function inOutQuad(t: number): number { return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; }\n export function inCubic(t: number): number { return t * t * t; }\n export function outCubic(t: number): number { return (--t) * t * t + 1; }\n export function inOutCubic(t: number): number { return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; }\n}\n\nnamespace light {\n export class BrightnessTransition {\n constructor() { }\n apply(strip: LightStrip, t: number, start: number, end: number): void {\n\n }\n }\n\n export class EasingBrightnessTransition extends BrightnessTransition {\n private timeEasing: (t: number) => number;\n private spatialEasing: (t: number) => number;\n\n constructor(\n timeEasing: (t: number) => number, \n spatialEasing?: (t: number) => number) {\n super();\n this.timeEasing = timeEasing || easing.inOutQuad;\n this.spatialEasing = spatialEasing;\n }\n\n apply(strip: LightStrip, t: number, start: number, end: number): void {\n // t in [0..1]\n const db = end - start;\n const b = this.timeEasing(t); // [0..1]\n if (!this.spatialEasing) {\n strip.setBrightness(start + db * b);\n }\n else {\n // convolve desired brightness with spacial easing function\n const n = strip.length();\n for (let i = 0; i < n; ++i) {\n const x = this.spatialEasing(i / (n - 1)); // [0..1]\n strip.setPixelBrightness(i, end - db * (1 - b) * x);\n }\n }\n }\n }\n\n export class BrightnessTransitionPlayer {\n private transition: BrightnessTransition;\n private startBrightness: number;\n private endBrightness: number;\n private duration: number;\n private startTime: number;\n private repeat: number;\n private yoyo: number;\n\n constructor(\n transition: BrightnessTransition,\n startBrightness: number,\n endBrightness: number,\n duration: number,\n repeat: number,\n yoyo: boolean) {\n this.transition = transition;\n this.startBrightness = startBrightness;\n this.endBrightness = endBrightness;\n this.duration = duration;\n this.startTime = control.millis();\n this.repeat = repeat || 1;\n this.yoyo = yoyo ? 1 : 0;\n }\n\n update(strip: LightStrip): boolean {\n let elapsed = control.millis() - this.startTime;\n if (elapsed > this.duration) {\n this.yoyo = -this.yoyo;\n if (this.repeat > 0)\n this.repeat--;\n this.startTime = control.millis();\n elapsed = 0;\n return this.repeat != 0;\n }\n\n let t = elapsed / this.duration;\n if (this.yoyo < 0)\n t = 1 - t;\n this.transition.apply(strip, t, this.startBrightness, this.endBrightness);\n return true;\n }\n }\n}"
@@ -1817,7 +1817,7 @@ var pxtTargetBundle = {
1817
1817
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum LightCondition {\n //% block=\"dark\"\n Dark = 1, // SENSOR_THRESHOLD_LOW\n //% block=\"bright\"\n Bright = 2, // SENSOR_THRESHOLD_HIGH\n }\n\n// Auto-generated. Do not edit. Really.\n",
1818
1818
  "lightsensor.cpp": "#include \"pxt.h\"\n#include \"AnalogSensor.h\"\n\n#ifdef CODAL_LIGHT_SENSOR_HEADER\n#include CODAL_LIGHT_SENSOR_HEADER\n#endif\n\n\n#ifndef CODAL_LIGHT_SENSOR\n#define CODAL_LIGHT_SENSOR AnalogSensor\n#endif\n\n#ifndef LIGHTSENSOR_SENSITIVITY\n#define LIGHTSENSOR_SENSITIVITY 868 // codal has 912 now\n#endif\n\n#ifndef LIGHTSENSOR_LOW_THRESHOLD\n#define LIGHTSENSOR_LOW_THRESHOLD 128\n#endif\n\n#ifndef LIGHTSENSOR_HIGH_THRESHOLD\n#define LIGHTSENSOR_HIGH_THRESHOLD 896\n#endif\n\nenum class LightCondition {\n //% block=\"dark\"\n Dark = SENSOR_THRESHOLD_LOW,\n //% block=\"bright\"\n Bright = SENSOR_THRESHOLD_HIGH\n};\n\nnamespace pxt {\n\nclass WLight {\n public:\n CODAL_LIGHT_SENSOR sensor;\n WLight()\n : sensor(*LOOKUP_PIN(LIGHT), DEVICE_ID_LIGHT_SENSOR) //\n {\n sensor.init();\n sensor.setPeriod(50);\n sensor.setSensitivity(LIGHTSENSOR_SENSITIVITY); \n sensor.setLowThreshold(LIGHTSENSOR_LOW_THRESHOLD);\n sensor.setHighThreshold(LIGHTSENSOR_HIGH_THRESHOLD);\n }\n};\nSINGLETON_IF_PIN(WLight, LIGHT);\n\n}\n\nnamespace input {\n\n/**\n* Register an event that runs when light conditions (darker or brighter) change.\n* @param condition the condition that event triggers on\n*/\n//% help=input/on-light-condition-changed\n//% blockId=input_on_light_condition_changed block=\"on light %condition\"\n//% parts=\"lightsensor\"\n//% weight=84 blockGap=12\nvoid onLightConditionChanged(LightCondition condition, Action handler) {\n auto wlight = getWLight();\n if (NULL == wlight) return; \n auto sensor = wlight->sensor;\n\n sensor.updateSample();\n registerWithDal(sensor.id, (int)condition, handler);\n}\n\n/**\n * Read the light level applied to the LED screen in a range from 0 (dark) to 255 (bright).\n */\n//% help=input/light-level\n//% blockId=device_get_light_level block=\"light level\"\n//% parts=\"lightsensor\"\n//% weight=30 blockGap=8\nint lightLevel() {\n auto wlight = getWLight();\n if (NULL == wlight) return 127;\n auto sensor = wlight->sensor;\n // 0...1023\n int value = sensor.getValue();\n return value / 4;\n}\n\n/**\n* Set the threshold value for the light condition event.\n*/\n//% help=input/set-light-threshold\n//% blockId=lightsensor_set_threshold block=\"set %condition| light threshold to %value\"\n//% parts=\"lightsensor\"\n//% value.min=1 value.max=255\n//% group=\"More\" weight=13 blockGap=8\nvoid setLightThreshold(LightCondition condition, int value) {\n auto wlight = getWLight();\n if (NULL == wlight) return;\n auto sensor = wlight->sensor;\n\n int v = value * 4;\n if (condition == LightCondition::Dark)\n sensor.setLowThreshold(v);\n else\n sensor.setHighThreshold(v);\n}\n}\n",
1819
1819
  "ns.ts": "\n//% color=\"#B4009E\" weight=98 icon=\"\\uf192\"\nnamespace input {\n}",
1820
- "pxt.json": "{\n \"name\": \"lightsensor\",\n \"description\": \"Onboard light level sensor\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"lightsensor.cpp\",\n \"ns.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1820
+ "pxt.json": "{\n \"name\": \"lightsensor\",\n \"description\": \"Onboard light level sensor\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"lightsensor.cpp\",\n \"ns.ts\",\n \"shims.d.ts\",\n \"enums.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
1821
1821
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace input {\n\n /**\n * Register an event that runs when light conditions (darker or brighter) change.\n * @param condition the condition that event triggers on\n */\n //% help=input/on-light-condition-changed\n //% blockId=input_on_light_condition_changed block=\"on light %condition\"\n //% parts=\"lightsensor\"\n //% weight=84 blockGap=12 shim=input::onLightConditionChanged\n function onLightConditionChanged(condition: LightCondition, handler: () => void): void;\n\n /**\n * Read the light level applied to the LED screen in a range from 0 (dark) to 255 (bright).\n */\n //% help=input/light-level\n //% blockId=device_get_light_level block=\"light level\"\n //% parts=\"lightsensor\"\n //% weight=30 blockGap=8 shim=input::lightLevel\n function lightLevel(): int32;\n\n /**\n * Set the threshold value for the light condition event.\n */\n //% help=input/set-light-threshold\n //% blockId=lightsensor_set_threshold block=\"set %condition| light threshold to %value\"\n //% parts=\"lightsensor\"\n //% value.min=1 value.max=255\n //% group=\"More\" weight=13 blockGap=8 shim=input::setLightThreshold\n function setLightThreshold(condition: LightCondition, value: int32): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
1822
1822
  "test.ts": "for(let i = 0; i < 100; ++i) {\n pause(500)\n console.log(`light=${input.lightLevel()}`);\n}"
1823
1823
  },
@@ -1826,7 +1826,7 @@ var pxtTargetBundle = {
1826
1826
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare enum LoudnessCondition {\n //% block=\"quiet\"\n Quiet = 1, // LEVEL_THRESHOLD_LOW\n //% block=\"loud\"\n Loud = 2, // LEVEL_THRESHOLD_HIGH\n }\n\n// Auto-generated. Do not edit. Really.\n",
1827
1827
  "microphone.cpp": "#include \"pxt.h\"\n#include \"LevelDetector.h\"\n#include \"LevelDetectorSPL.h\"\n\n#define MICROPHONE_MIN 52.0f\n#define MICROPHONE_MAX 120.0f\n\nnamespace pxt {\n codal::LevelDetectorSPL* getMicrophoneLevel();\n}\n\nnamespace input {\n/**\n* Registers an event that runs when a loud sound is detected\n*/\n//% help=input/on-loud-sound\n//% blockId=input_on_loud_sound block=\"on loud sound\"\n//% parts=\"microphone\"\n//% weight=88 blockGap=12\nvoid onLoudSound(Action handler) {\n pxt::getMicrophoneLevel(); // wake up service\n registerWithDal(DEVICE_ID_MICROPHONE, LEVEL_THRESHOLD_HIGH, handler);\n}\n\n/**\n* Reads the loudness through the microphone from 0 (silent) to 255 (loud)\n*/\n//% help=input/sound-level\n//% blockId=device_get_sound_level block=\"sound level\"\n//% parts=\"microphone\"\n//% weight=34 blockGap=8\nint soundLevel() {\n auto level = pxt::getMicrophoneLevel();\n if (NULL == level)\n return MICROPHONE_MIN; \n const int micValue = level->getValue();\n const int scaled = max(MICROPHONE_MIN, min(micValue, MICROPHONE_MAX)) - MICROPHONE_MIN;\n return min(0xff, scaled * 0xff / (MICROPHONE_MAX - MICROPHONE_MIN));\n}\n\n/**\n* Sets the minimum threshold for a loud sound\n*/\n//% help=input/set-loud-sound-threshold\n//% blockId=input_set_loud_sound_threshold block=\"set loud sound threshold %value\"\n//% parts=\"microphone\"\n//% value.min=1 value.max=255\n//% group=\"More\" weight=14 blockGap=8\nvoid setLoudSoundThreshold(int value) {\n auto level = pxt::getMicrophoneLevel();\n if (NULL == level)\n return;\n\n value = max(0, min(0xff, value));\n const int scaled = MICROPHONE_MIN + value * (MICROPHONE_MAX - MICROPHONE_MIN) / 0xff;\n level->setHighThreshold(scaled);\n}\n}",
1828
1828
  "microphonehw.cpp": "#include \"pxt.h\"\n#include \"LevelDetector.h\"\n#include \"LevelDetectorSPL.h\"\n#include \"DataStream.h\"\n\n#ifndef MIC_DEVICE\n// STM?\nclass DummyDataSource : public codal::DataSource {\n public:\n DummyDataSource() {}\n};\nclass PanicPDM {\n public:\n uint8_t level;\n DummyDataSource source;\n codal::DataStream output;\n\n PanicPDM(Pin &sd, Pin &sck) : output(source) { target_panic(PANIC_MICROPHONE_MISSING); }\n void enable() {}\n void disable() {}\n};\n#define MIC_DEVICE PanicPDM\n#endif\n\n#ifndef MIC_INIT\n#define MIC_INIT \\\n : microphone(*LOOKUP_PIN(MIC_DATA), *LOOKUP_PIN(MIC_CLOCK)) \\\n , level(microphone.output, 95.0, 75.0, 9, 52, DEVICE_ID_MICROPHONE)\n#endif\n\n#ifndef MIC_ENABLE\n#define MIC_ENABLE microphone.enable()\n#endif\n\nnamespace pxt {\n\nclass WMicrophone {\n public:\n MIC_DEVICE microphone;\n LevelDetectorSPL level;\n WMicrophone() MIC_INIT { MIC_ENABLE; }\n};\nSINGLETON(WMicrophone);\n\ncodal::LevelDetectorSPL *getMicrophoneLevel() {\n auto wmic = getWMicrophone();\n return wmic ? &(wmic->level) : NULL;\n}\n\n} // namespace pxt\n",
1829
- "pxt.json": "{\n \"name\": \"microphone\",\n \"description\": \"The microphone library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"microphone.cpp\",\n \"microphonehw.cpp\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true,\n \"icon\": \"/static/libs/microphone.png\"\n}\n",
1829
+ "pxt.json": "{\n \"name\": \"microphone\",\n \"description\": \"The microphone library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"microphone.cpp\",\n \"microphonehw.cpp\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true,\n \"icon\": \"/static/libs/microphone.png\"\n}\n",
1830
1830
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace input {\n\n /**\n * Registers an event that runs when a loud sound is detected\n */\n //% help=input/on-loud-sound\n //% blockId=input_on_loud_sound block=\"on loud sound\"\n //% parts=\"microphone\"\n //% weight=88 blockGap=12 shim=input::onLoudSound\n function onLoudSound(handler: () => void): void;\n\n /**\n * Reads the loudness through the microphone from 0 (silent) to 255 (loud)\n */\n //% help=input/sound-level\n //% blockId=device_get_sound_level block=\"sound level\"\n //% parts=\"microphone\"\n //% weight=34 blockGap=8 shim=input::soundLevel\n function soundLevel(): int32;\n\n /**\n * Sets the minimum threshold for a loud sound\n */\n //% help=input/set-loud-sound-threshold\n //% blockId=input_set_loud_sound_threshold block=\"set loud sound threshold %value\"\n //% parts=\"microphone\"\n //% value.min=1 value.max=255\n //% group=\"More\" weight=14 blockGap=8 shim=input::setLoudSoundThreshold\n function setLoudSoundThreshold(value: int32): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
1831
1831
  "targetoverrides.ts": "// target specific code",
1832
1832
  "test.ts": "// tests"
@@ -1843,7 +1843,7 @@ var pxtTargetBundle = {
1843
1843
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1844
1844
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1845
1845
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1846
- "pxt.json": "{\n \"name\": \"mixer\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1846
+ "pxt.json": "{\n \"name\": \"mixer\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1847
1847
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1848
1848
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1849
1849
  "sound.cpp": "// to be overridden\n",
@@ -1863,7 +1863,7 @@ var pxtTargetBundle = {
1863
1863
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1864
1864
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1865
1865
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1866
- "pxt.json": "{\n \"name\": \"mixer---ext\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1866
+ "pxt.json": "{\n \"name\": \"mixer---ext\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1867
1867
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1868
1868
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1869
1869
  "sound.cpp": "#include \"pxt.h\"\n#include \"SoundOutput.h\"\n#include \"melody.h\"\n\nnamespace music {\n\nstatic ExtDAC *dac;\n\nDLLEXPORT void pxt_get_audio_samples(int16_t *buf, unsigned numSamples) {\n if (!dac) {\n memset(buf, 0, numSamples * 2);\n return;\n }\n\n target_disable_irq();\n dac->src.fillSamples(buf, numSamples);\n target_enable_irq();\n\n for (unsigned i = 0; i < numSamples; ++i) {\n // playing at half-volume\n buf[i] = buf[i] << 3;\n }\n\n //DMESG(\"samples %d %d %d %d\", numSamples, buf[0], buf[20], buf[100]);\n}\n\nExtDAC::ExtDAC(WSynthesizer &data) : src(data) {\n dac = this;\n}\n\n} // namespace music",
@@ -1883,7 +1883,7 @@ var pxtTargetBundle = {
1883
1883
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1884
1884
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1885
1885
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1886
- "pxt.json": "{\n \"name\": \"mixer---linux\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1886
+ "pxt.json": "{\n \"name\": \"mixer---linux\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1887
1887
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1888
1888
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1889
1889
  "sound.cpp": "#include \"pxt.h\"\n#include \"SoundOutput.h\"\n#include \"melody.h\"\n\n#include <alsa/asoundlib.h>\n#include <pthread.h>\n\nnamespace music {\n\nstatic void alsa_check(int pos, int fn) {\n if (fn < 0) {\n DMESG(\"alsa fail! pos=%d err=%d: %s\", pos, fn, snd_strerror(fn));\n target_panic(950);\n }\n}\n\nvoid *LinuxDAC::play(void *self) {\n auto dac = (LinuxDAC *)self;\n\n snd_pcm_t *pcm_handle;\n\n sleep_core_us(1000 * 1000);\n\n alsa_check(0, snd_pcm_open(&pcm_handle, \"default\", SND_PCM_STREAM_PLAYBACK, 0));\n\n alsa_check(1, snd_pcm_set_params(pcm_handle, SND_PCM_FORMAT_S16_LE,\n SND_PCM_ACCESS_RW_INTERLEAVED, 1, SAMPLE_RATE, 1, 30 * 1000));\n\n DMESG(\"PCM name: '%s'\", snd_pcm_name(pcm_handle));\n DMESG(\"PCM state: %s\", snd_pcm_state_name(snd_pcm_state(pcm_handle)));\n\n for (;;) {\n target_disable_irq();\n auto hasData = dac->src.fillSamples(dac->data, sizeof(dac->data) / 2);\n target_enable_irq();\n auto len = (int)sizeof(dac->data) / 2;\n if (!hasData) {\n sleep_core_us(5000);\n continue;\n }\n for (int i = 0; i < len; ++i) {\n // playing at half-volume\n dac->data[i] = dac->data[i] << 3;\n }\n int frames = snd_pcm_writei(pcm_handle, dac->data, len);\n if (frames < 0)\n frames = snd_pcm_recover(pcm_handle, frames, 0);\n if (frames < 0) {\n DMESG(\"alsa write faield: %s\", snd_strerror(frames));\n target_panic(951);\n }\n }\n\n return NULL;\n}\n\nLinuxDAC::LinuxDAC(WSynthesizer &data) : src(data) {\n pthread_t upd;\n pthread_create(&upd, NULL, LinuxDAC::play, this);\n pthread_detach(upd);\n}\n\n}",
@@ -1903,7 +1903,7 @@ var pxtTargetBundle = {
1903
1903
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1904
1904
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1905
1905
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1906
- "pxt.json": "{\n \"name\": \"mixer---none\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1906
+ "pxt.json": "{\n \"name\": \"mixer---none\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1907
1907
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1908
1908
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1909
1909
  "sound.cpp": "// to be overridden\n",
@@ -1923,7 +1923,7 @@ var pxtTargetBundle = {
1923
1923
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1924
1924
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1925
1925
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1926
- "pxt.json": "{\n \"name\": \"mixer---nrf52\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1926
+ "pxt.json": "{\n \"name\": \"mixer---nrf52\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1927
1927
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1928
1928
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1929
1929
  "sound.cpp": "// to be overridden\n",
@@ -1943,7 +1943,7 @@ var pxtTargetBundle = {
1943
1943
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1944
1944
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1945
1945
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1946
- "pxt.json": "{\n \"name\": \"mixer---samd\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1946
+ "pxt.json": "{\n \"name\": \"mixer---samd\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1947
1947
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1948
1948
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1949
1949
  "sound.cpp": "// to be overridden\n",
@@ -1963,7 +1963,7 @@ var pxtTargetBundle = {
1963
1963
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1964
1964
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1965
1965
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1966
- "pxt.json": "{\n \"name\": \"mixer---stm32\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1966
+ "pxt.json": "{\n \"name\": \"mixer---stm32\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1967
1967
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1968
1968
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1969
1969
  "sound.cpp": "// to be overridden\n",
@@ -1983,7 +1983,7 @@ var pxtTargetBundle = {
1983
1983
  "ns.ts": "\n/**\n * Generation of music tones.\n */\n//% color=#E30FC0 weight=90 icon=\"\\uf025\"\n//% blockGap=8\n//% groups='[\"Songs\", \"Sounds\", \"Tone\", \"Volume\", \"Tempo\"]'\nnamespace music {\n}",
1984
1984
  "piano.ts": "namespace music {\n /**\n * Get the frequency of a note.\n * @param name the note name, eg: Note.C\n */\n //% weight=1 help=music/note-frequency\n //% blockId=device_note block=\"%note\"\n //% shim=TD_ID\n //% color=\"#FFFFFF\" colorSecondary=\"#FFFFFF\" colorTertiary=\"#D83B01\"\n //% note.fieldEditor=\"note\" note.defl=\"262\"\n //% note.fieldOptions.decompileLiterals=true\n //% useEnumVal=1\n //% weight=10 blockGap=8\n //% group=\"Tone\"\n export function noteFrequency(name: Note): number {\n return name;\n }\n}",
1985
1985
  "playable.ts": "namespace music {\n export enum PlaybackMode {\n //% block=\"until done\"\n UntilDone,\n //% block=\"in background\"\n InBackground,\n //% block=\"looping in background\"\n LoopingInBackground\n }\n\n let stateStack: PlayableState[];\n\n class PlayableState {\n looping: Playable[];\n constructor() {\n this.looping = [];\n }\n\n stopLooping() {\n for (const p of this.looping) {\n p.stopped = true;\n }\n this.looping = [];\n }\n }\n\n function state() {\n _init();\n return stateStack[stateStack.length - 1];\n }\n\n function _init() {\n if (stateStack) return;\n stateStack = [new PlayableState()];\n\n game.addScenePushHandler(() => {\n stateStack.push(new PlayableState());\n });\n\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new PlayableState());\n });\n }\n\n export class Playable {\n stopped: boolean;\n constructor() {\n\n }\n\n play(playbackMode: PlaybackMode) {\n // subclass\n }\n\n loop() {\n state().looping.push(this);\n this.stopped = false;\n\n control.runInParallel(() => {\n while (!this.stopped) {\n this.play(PlaybackMode.UntilDone);\n }\n });\n }\n }\n\n export class MelodyPlayable extends Playable {\n constructor(public melody: Melody) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n this.melody.play(music.volume());\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n this.melody.playUntilDone(music.volume());\n }\n else {\n this.melody.loop(music.volume());\n }\n }\n }\n\n export class TonePlayable extends Playable {\n constructor(public pitch: number, public duration: number) {\n super();\n }\n\n play(playbackMode: PlaybackMode) {\n if (playbackMode === PlaybackMode.InBackground) {\n control.runInParallel(() => music.playTone(this.pitch, this.duration));\n }\n else if (playbackMode === PlaybackMode.UntilDone) {\n music.playTone(this.pitch, this.duration);\n if (this.duration > 2000) {\n pause(this.duration);\n }\n }\n else {\n this.loop();\n }\n }\n }\n\n //% blockId=\"music_playable_play\"\n //% block=\"play $toPlay $playbackMode\"\n //% toPlay.shadow=music_melody_playable\n //% group=\"Sounds\"\n export function play(toPlay: Playable, playbackMode: PlaybackMode) {\n toPlay.play(playbackMode);\n }\n\n //% blockId=\"music_melody_playable\"\n //% block=\"sound $melody\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Sounds\"\n //% duplicateShadowOnDrag\n //% blockHidden\n export function melodyPlayable(melody: Melody): Playable {\n return new MelodyPlayable(melody);\n }\n\n\n //% blockId=\"music_string_playable\"\n //% block=\"melody $melody at tempo $tempo|(bpm)\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% weight=85 blockGap=8\n //% help=music/melody-editor\n //% group=\"Songs\"\n //% duplicateShadowOnDrag\n //% melody.shadow=melody_editor\n //% tempo.min=40 tempo.max=500\n //% tempo.defl=120\n export function stringPlayable(melody: string, tempo: number): Playable {\n let notes: string[] = melody.split(\" \").filter(n => !!n);\n let formattedMelody = \"\";\n let newOctave = false;\n\n // build melody string, replace '-' with 'R' and add tempo\n // creates format like \"C5-174 B4 A G F E D C \"\n for (let i = 0; i < notes.length; i++) {\n if (notes[i] === \"-\") {\n notes[i] = \"R\";\n } else if (notes[i] === \"C5\") {\n newOctave = true;\n } else if (newOctave) { // change the octave if necesary\n notes[i] += \"4\";\n newOctave = false;\n }\n // add tempo after first note\n if (i == 0) {\n formattedMelody += notes[i] + \"-\" + tempo + \" \";\n } else {\n formattedMelody += notes[i] + \" \";\n }\n }\n\n return new MelodyPlayable(new Melody(formattedMelody));\n }\n\n //% blockId=\"music_tone_playable\"\n //% block=\"tone $note for $duration\"\n //% toolboxParent=music_playable_play\n //% toolboxParentArgument=toPlay\n //% group=\"Tone\"\n //% duplicateShadowOnDrag\n //% note.shadow=device_note\n //% duration.shadow=device_beat\n //% parts=\"headphone\"\n export function tonePlayable(note: number, duration: number): Playable {\n return new TonePlayable(note, duration);\n }\n\n export function _stopPlayables() {\n state().stopLooping();\n }\n}",
1986
- "pxt.json": "{\n \"name\": \"mixer---rp2040\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1986
+ "pxt.json": "{\n \"name\": \"mixer---rp2040\",\n \"description\": \"The music library with a mixer\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"SoundOutput.h\",\n \"sound.cpp\",\n \"melody.h\",\n \"melody.cpp\",\n \"melody.ts\",\n \"piano.ts\",\n \"legacy.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"music.ts\",\n \"soundEffect.ts\",\n \"instrument.ts\",\n \"sequencer.ts\",\n \"playable.ts\",\n \"pxtparts.json\",\n \"headphone.svg\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
1987
1987
  "pxtparts.json": "{\n \"headphone\": {\n \"numberOfPins\": 2,\n \"visual\": {\n \"image\": \"headphone.svg\",\n \"width\": 142,\n \"height\": 180,\n \"pinDistance\": 20,\n \"pinLocations\": [\n {\n \"x\": 17,\n \"y\": 11\n },\n {\n \"x\": 55,\n \"y\": 50\n }\n ]\n },\n \"pinDefinitions\": [\n {\n \"target\": \"A0\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n },\n {\n \"target\": \"ground\",\n \"style\": \"croc\",\n \"orientation\": \"Y\"\n }\n ],\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"assembly\": [\n {\n \"part\": true,\n \"pinIndices\": [\n 0\n ]\n },\n {\n \"pinIndices\": [\n 1\n ]\n }\n ]\n }\n}",
1988
1988
  "sequencer.ts": "namespace music.sequencer {\n export class Sequencer {\n currentTick: number;\n isPlaying: boolean;\n isLooping: boolean;\n isRunning: boolean;\n\n constructor(public song: Song) {\n this.currentTick = 0;\n this.isPlaying = false;\n this.isLooping = false;\n }\n\n start(loop: boolean) {\n this.currentTick = 0;\n this.isLooping = loop;\n this.isPlaying = true;\n\n if (this.isRunning) return;\n this.isRunning = true;\n\n control.runInParallel(() => {\n while (this.isPlaying) {\n this.scheduleCurrentTick();\n\n this.currentTick ++;\n\n if (this.currentTick >= this.song.beatsPerMeasure * this.song.measures * this.song.ticksPerBeat) {\n if (this.isLooping) this.currentTick = 0;\n else this.isPlaying = false;\n }\n\n pause(this.tickToMs(1))\n }\n this.isRunning = false;\n })\n }\n\n stop() {\n this.isPlaying = false;\n }\n\n tickToMs(ticks: number) {\n return ((60000 / this.song.beatsPerMinute) / this.song.ticksPerBeat) * ticks;\n }\n\n protected scheduleCurrentTick() {\n for (const track of this.song.tracks) {\n if (track.currentNoteEvent.startTick === this.currentTick) {\n if (track.isMelodicTrack) {\n this.scheduleMelodicTrack(track as MelodicTrack);\n }\n else {\n this.scheduleDrumTrack(track as DrumTrack);\n }\n\n track.advanceNoteEvent();\n }\n }\n }\n\n protected scheduleMelodicTrack(track: MelodicTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderInstrument(\n track.instrument,\n lookupFrequency(track.currentNoteEvent.getNote(i, track.instrument.octave)),\n this.tickToMs(track.currentNoteEvent.endTick - track.currentNoteEvent.startTick),\n music.volume()\n )\n );\n }\n }\n\n protected scheduleDrumTrack(track: DrumTrack) {\n for (let i = 0; i < track.currentNoteEvent.polyphony; i++) {\n playInstructions(\n 0,\n renderDrumInstrument(\n track.drums[track.currentNoteEvent.getNote(i, undefined)],\n music.volume()\n )\n );\n }\n }\n }\n}",
1989
1989
  "sound.cpp": "// to be overridden\n",
@@ -1995,13 +1995,13 @@ var pxtTargetBundle = {
1995
1995
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum MouseButton {\n //% block=\"left\" enumval=1\n Left = 0x01,\n //% block=\"right\" enumval=2\n Right = 0x02,\n //% block=\"middle\" enumval=4\n Middle = 0x04,\n }\n\n// Auto-generated. Do not edit. Really.\n",
1996
1996
  "mouse.cpp": "// https://github.com/lancaster-university/codal-core/blob/master/source/drivers/HIDMouse.cpp\n\n#include \"pxt.h\"\n\nenum class MouseButton {\n //% block=\"left\" enumval=1\n Left = 0x01,\n //% block=\"right\" enumval=2\n Right = 0x02,\n //% block=\"middle\" enumval=4\n Middle = 0x04\n};\n\nnamespace mouse {\n /** \n * Set the mouse button state to up or down\n */\n //% help=mouse/set-button\n //% blockId=mouseSetButton block=\"mouse button %index|%down=toggleDownUp\"\n void setButton(MouseButton button, bool down) {\n if (down)\n pxt::mouse.buttonDown((codal::USBHIDMouseButton)button);\n else\n pxt::mouse.buttonUp((codal::USBHIDMouseButton)button);\n }\n\n /**\n * Move the mouse in the X and Y direction\n **/\n //% help=mouse/move\n //% blockId=mouseMove block=\"mouse move x %x|y %y\"\n //% x.min=-128 x.max=127\n //% y.min=-128 y.max=127\n void move(int x, int y) {\n pxt::mouse.move(x, y);\n }\n\n /**\n * Turn the mouse wheel\n **/\n //% help=mouse/turn-wheel\n //% blockId=mouseWheel block=\"mouse turn wheel %w\"\n //% w.min=-128 w.max=127\n void turnWheel(int w) {\n pxt::mouse.moveWheel(w);\n }\n}",
1997
1997
  "mouse.ts": "/**\n * Mouse emulation\n */\n//% icon=\"\\uf245\" color=\"#303030\"\nnamespace mouse {\n /**\n * Generates a mouse click\n * @param button the button to click\n */\n //% help=mouse/click\n //% blockId=mouseClick block=\"mouse click button $button\"\n //% weight=100\n export function click(button: MouseButton): void {\n mouse.setButton(button, true)\n mouse.setButton(button, false)\n }\n}",
1998
- "pxt.json": "{\n \"name\": \"mouse\",\n \"description\": \"Mouse emulation over HID\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"mouse.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"mouse.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"tests\": [\n \"test.ts\"\n ],\n \"yotta\": {\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_MOUSE\": 1\n }\n },\n \"icon\": \"/static/libs/mouse.png\"\n}\n",
1998
+ "pxt.json": "{\n \"name\": \"mouse\",\n \"description\": \"Mouse emulation over HID\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"mouse.cpp\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"mouse.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"tests\": [\n \"test.ts\"\n ],\n \"yotta\": {\n \"config\": {\n \"DEVICE_USB\": 1,\n \"DEVICE_MOUSE\": 1\n }\n },\n \"icon\": \"/static/libs/mouse.png\"\n}\n",
1999
1999
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace mouse {\n\n /** \n * Set the mouse button state to up or down\n */\n //% help=mouse/set-button\n //% blockId=mouseSetButton block=\"mouse button %index|%down=toggleDownUp\" shim=mouse::setButton\n function setButton(button: MouseButton, down: boolean): void;\n\n /**\n * Move the mouse in the X and Y direction\n **/\n //% help=mouse/move\n //% blockId=mouseMove block=\"mouse move x %x|y %y\"\n //% x.min=-128 x.max=127\n //% y.min=-128 y.max=127 shim=mouse::move\n function move(x: int32, y: int32): void;\n\n /**\n * Turn the mouse wheel\n **/\n //% help=mouse/turn-wheel\n //% blockId=mouseWheel block=\"mouse turn wheel %w\"\n //% w.min=-128 w.max=127 shim=mouse::turnWheel\n function turnWheel(w: int32): void;\n}\n\n// Auto-generated. Do not edit. Really.\n"
2000
2000
  },
2001
2001
  "mqtt": {
2002
2002
  "README.md": "# MQTT\n\nMQTT communication layer. A port of https://github.com/rovale/micro-mqtt for MakeCode.\n",
2003
2003
  "mqtt.ts": "namespace mqtt {\n /**\n * Connect flags\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349229\n */\n export const enum ConnectFlags {\n UserName = 128,\n Password = 64,\n WillRetain = 32,\n WillQoS2 = 16,\n WillQoS1 = 8,\n Will = 4,\n CleanSession = 2\n }\n\n /**\n * Connect Return code\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349256\n */\n export const enum ConnectReturnCode {\n Unknown = -1,\n Accepted = 0,\n UnacceptableProtocolVersion = 1,\n IdentifierRejected = 2,\n ServerUnavailable = 3,\n BadUserNameOrPassword = 4,\n NotAuthorized = 5\n }\n\n /**\n * A message received in a Publish packet.\n */\n export interface IMessage {\n pid?: number;\n topic: string;\n content: Buffer;\n qos: number;\n retain: number;\n }\n\n /**\n * MQTT Control Packet type\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc353481061\n */\n export const enum ControlPacketType {\n Connect = 1,\n ConnAck = 2,\n Publish = 3,\n PubAck = 4,\n // PubRec = 5,\n // PubRel = 6,\n // PubComp = 7,\n Subscribe = 8,\n SubAck = 9,\n Unsubscribe = 10,\n UnsubAck = 11,\n PingReq = 12,\n PingResp = 13,\n Disconnect = 14\n }\n\n /**\n * Optimization, the TypeScript compiler replaces the constant enums.\n */\n export const enum Constants {\n PingInterval = 40,\n WatchDogInterval = 50,\n DefaultQos = 0,\n Uninitialized = -123,\n FixedPackedId = 1,\n KeepAlive = 60\n }\n\n /**\n * The options used to connect to the MQTT broker.\n */\n export interface IConnectionOptions {\n host: string;\n port?: number;\n username?: string;\n password?: string;\n clientId: string;\n will?: IConnectionOptionsWill;\n }\n\n export interface IConnectionOptionsWill {\n topic: string;\n message: string;\n qos?: number;\n retain?: boolean;\n }\n\n /**\n * The specifics of the MQTT protocol.\n */\n export module Protocol {\n function strChr(codes: number[]): Buffer {\n return pins.createBufferFromArray(codes)\n }\n\n /**\n * Encode remaining length\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718023\n */\n function encodeRemainingLength(remainingLength: number): number[] {\n let length: number = remainingLength;\n const encBytes: number[] = [];\n do {\n let encByte: number = length & 127;\n length = length >> 7;\n // if there are more data to encode, set the top bit of this byte\n if (length > 0) {\n encByte += 128;\n }\n encBytes.push(encByte);\n } while (length > 0);\n\n return encBytes;\n }\n\n /**\n * Connect flags\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349229\n */\n function createConnectFlags(options: IConnectionOptions): number {\n let flags: number = 0;\n flags |= (options.username) ? ConnectFlags.UserName : 0;\n flags |= (options.username && options.password) ? ConnectFlags.Password : 0;\n flags |= ConnectFlags.CleanSession;\n\n if (options.will) {\n flags |= ConnectFlags.Will;\n flags |= (options.will.qos || 0) << 3;\n flags |= (options.will.retain) ? ConnectFlags.WillRetain : 0;\n }\n\n return flags;\n }\n\n // Returns the MSB and LSB.\n function getBytes(int16: number): number[] {\n return [int16 >> 8, int16 & 255];\n }\n\n /**\n * Structure of UTF-8 encoded strings\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Figure_1.1_Structure\n */\n function pack(s: string): Buffer {\n const buf = control.createBufferFromUTF8(s);\n return strChr(getBytes(buf.length)).concat(buf);\n }\n\n /**\n * Structure of an MQTT Control Packet\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800392\n */\n function createPacketHeader(byte1: number, variable: Buffer, payloadSize: number): Buffer {\n const byte2: number[] = encodeRemainingLength(variable.length + payloadSize);\n return strChr([byte1])\n .concat(strChr(byte2))\n .concat(variable)\n }\n\n /**\n * Structure of an MQTT Control Packet\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800392\n */\n function createPacket(byte1: number, variable: Buffer, payload?: Buffer): Buffer {\n if (payload == null) payload = control.createBuffer(0);\n return createPacketHeader(byte1, variable, payload.length).concat(payload)\n }\n\n /**\n * CONNECT - Client requests a connection to a Server\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028\n */\n export function createConnect(options: IConnectionOptions): Buffer {\n const byte1: number = ControlPacketType.Connect << 4;\n\n const protocolName = pack('MQTT');\n const nums = control.createBuffer(4)\n nums[0] = 4; // protocol level\n nums[1] = createConnectFlags(options)\n nums[2] = 0\n nums[3] = Constants.KeepAlive\n\n let payload = pack(options.clientId);\n\n if (options.will) {\n payload = payload\n .concat(pack(options.will.topic)\n .concat(pack(options.will.message)));\n }\n\n if (options.username) {\n payload = payload.concat(pack(options.username));\n if (options.password) {\n payload = payload.concat(pack(options.password));\n }\n }\n\n return createPacket(\n byte1,\n protocolName.concat(nums),\n payload\n );\n }\n\n /** PINGREQ - PING request\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800454\n */\n export function createPingReq() {\n return strChr([ControlPacketType.PingReq << 4, 0]);\n }\n\n /**\n * PUBLISH - Publish message header - doesn't include \"payload\"\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800410\n */\n export function createPublishHeader(topic: string, payloadSize: number, qos: number, retained: boolean) {\n let byte1: number = ControlPacketType.Publish << 4 | (qos << 1);\n byte1 |= (retained) ? 1 : 0;\n\n const pid = strChr(getBytes(Constants.FixedPackedId));\n const variable = (qos === 0) ? pack(topic) : pack(topic).concat(pid);\n\n return createPacketHeader(byte1, variable, payloadSize);\n }\n\n export function parsePublish(cmd: number, payload: Buffer): IMessage {\n const qos: number = (cmd & 0b00000110) >> 1;\n\n const topicLength = payload.getNumber(NumberFormat.UInt16BE, 0);\n let variableLength: number = 2 + topicLength;\n if (qos > 0) {\n variableLength += 2;\n }\n\n const message: IMessage = {\n topic: payload.slice(2, topicLength).toString(),\n content: payload.slice(variableLength),\n qos: qos,\n retain: cmd & 1\n };\n\n if (qos > 0)\n message.pid = payload.getNumber(NumberFormat.UInt16BE, variableLength - 2);\n\n return message;\n }\n\n /**\n * PUBACK - Publish acknowledgement\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800416\n */\n export function createPubAck(pid: number) {\n const byte1: number = ControlPacketType.PubAck << 4;\n\n return createPacket(byte1, strChr(getBytes(pid)));\n }\n\n /**\n * SUBSCRIBE - Subscribe to topics\n * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800436\n */\n export function createSubscribe(topic: string, qos: number): Buffer {\n const byte1: number = ControlPacketType.Subscribe << 4 | 2;\n const pid = strChr(getBytes(Constants.FixedPackedId));\n\n return createPacket(byte1,\n pid,\n pack(topic).concat(strChr([qos])))\n }\n }\n\n export type EventHandler = (arg?: string | IMessage) => void;\n\n export class EventEmitter {\n private handlers: { [index: string]: EventHandler[] };\n\n constructor() {\n this.handlers = {};\n }\n\n public on(event: string, listener: EventHandler): void {\n if (!event || !listener) return;\n\n let listeners = this.handlers[event];\n if (!listeners)\n this.handlers[event] = listeners = [];\n listeners.push(listener);\n }\n protected emit(event: string, arg?: string | IMessage): boolean {\n let listeners = this.handlers[event];\n if (listeners) {\n listeners.forEach(listener => listener(arg));\n }\n return true;\n }\n }\n\n enum HandlerStatus {\n Normal = 0,\n Once = 1,\n ToRemove = 2,\n }\n\n class MQTTHandler {\n public status: HandlerStatus\n constructor(\n public topic: string,\n public handler: (m: IMessage) => void\n ) {\n this.status = HandlerStatus.Normal\n }\n }\n\n export enum Status {\n Disconnected = 0,\n Connecting = 1,\n Connected = 2,\n Sending = 3,\n }\n\n export class Client extends EventEmitter {\n public logPriority = ConsolePriority.Debug\n public tracePriority = -1 as ConsolePriority;\n\n private log(msg: string) {\n console.add(this.logPriority, `mqtt: ${msg}`);\n }\n\n private trace(msg: string) {\n console.add(this.tracePriority, `mqtt: ${msg}`);\n }\n\n public opt: IConnectionOptions;\n\n private net: net.Net;\n private sct?: net.Socket;\n\n private wdId: number;\n private piId: number;\n\n private buf: Buffer;\n // we re-send subscriptions on re-connect\n private subs: Buffer[] = [];\n\n public status = Status.Disconnected\n\n get connected() {\n return this.status >= Status.Connected\n }\n\n private mqttHandlers: MQTTHandler[];\n\n constructor(opt: IConnectionOptions) {\n super();\n\n this.wdId = Constants.Uninitialized;\n this.piId = Constants.Uninitialized;\n opt.port = opt.port || 8883;\n opt.clientId = opt.clientId;\n\n if (opt.will) {\n opt.will.qos = opt.will.qos || Constants.DefaultQos;\n opt.will.retain = opt.will.retain || false;\n }\n\n this.opt = opt;\n this.net = net.instance();\n }\n\n private static describe(code: ConnectReturnCode): string {\n let error: string = 'Connection refused, ';\n switch (code) {\n case ConnectReturnCode.UnacceptableProtocolVersion:\n error += 'unacceptable protocol version.';\n break;\n case ConnectReturnCode.IdentifierRejected:\n error += 'identifier rejected.';\n break;\n case ConnectReturnCode.ServerUnavailable:\n error += 'server unavailable.';\n break;\n case ConnectReturnCode.BadUserNameOrPassword:\n error += 'bad user name or password.';\n break;\n case ConnectReturnCode.NotAuthorized:\n error += 'not authorized.';\n break;\n default:\n error += `unknown return code: ${code}.`;\n }\n\n return error;\n }\n\n public disconnect(): void {\n this.log(\"disconnect\")\n if (this.wdId !== Constants.Uninitialized) {\n clearInterval(this.wdId);\n this.wdId = Constants.Uninitialized;\n }\n\n if (this.piId !== Constants.Uninitialized) {\n clearInterval(this.piId);\n this.piId = Constants.Uninitialized;\n }\n\n const s = this.sct\n if (s) {\n this.sct = null\n s.close()\n }\n\n this.status = Status.Disconnected\n }\n\n public connect(): void {\n if (this.status != Status.Disconnected)\n return\n this.status = Status.Connecting\n this.log(`Connecting to ${this.opt.host}:${this.opt.port}`);\n if (this.wdId === Constants.Uninitialized) {\n this.wdId = setInterval(() => {\n if (!this.connected) {\n this.emit('disconnected');\n this.emit('error', 'No connection. Retrying.');\n this.disconnect();\n this.connect();\n }\n }, Constants.WatchDogInterval * 1000);\n }\n\n this.sct = this.net.createSocket(this.opt.host, this.opt.port, true);\n this.sct.onOpen(() => {\n this.log('Network connection established.');\n this.emit('connect');\n this.send(Protocol.createConnect(this.opt));\n });\n this.sct.onMessage((msg: Buffer) => {\n this.trace(\"incoming \" + msg.length + \" bytes\")\n this.handleMessage(msg);\n });\n this.sct.onError(() => {\n this.log('Error.');\n this.emit('error');\n });\n this.sct.onClose(() => {\n this.log('Close.');\n this.emit('disconnected');\n this.status = Status.Disconnected\n this.sct = null;\n });\n this.sct.connect();\n }\n\n private canSend() {\n let cnt = 0\n while (true) {\n if (this.status == Status.Connected) {\n this.status = Status.Sending\n return true\n }\n if (cnt++ < 100 && this.status == Status.Sending)\n pause(20)\n else {\n this.log(\"drop pkt\")\n return false\n }\n }\n }\n\n private doneSending() {\n this.trace(\"done send\")\n if (this.status == Status.Sending)\n this.status = Status.Connected\n }\n\n // Publish a message\n public publish(topic: string, message?: string | Buffer, qos: number = Constants.DefaultQos, retained: boolean = false): void {\n const buf = typeof message == \"string\" ? control.createBufferFromUTF8(message) : message\n message = null\n if (this.startPublish(topic, buf ? buf.length : 0, qos, retained)) {\n if (buf)\n this.send(buf);\n this.finishPublish()\n }\n }\n\n public startPublish(topic: string, messageLen: number, qos: number = Constants.DefaultQos, retained: boolean = false) {\n if (!this.canSend()) return false\n this.trace(`publish: ${topic} ${messageLen}b`)\n this.send(Protocol.createPublishHeader(topic, messageLen, qos, retained));\n return true\n }\n\n public continuePublish(data: Buffer) {\n this.send(data)\n }\n\n public finishPublish() {\n this.doneSending()\n this.emit(\"published\")\n }\n\n private subscribeCore(topic: string, handler: (msg: IMessage) => void, qos: number = Constants.DefaultQos): MQTTHandler {\n this.log(`subscribe: ${topic}`)\n const sub = Protocol.createSubscribe(topic, qos)\n this.subs.push(sub)\n this.send1(sub);\n if (handler) {\n if (topic[topic.length - 1] == \"#\")\n topic = topic.slice(0, topic.length - 1)\n if (!this.mqttHandlers) this.mqttHandlers = []\n const h = new MQTTHandler(topic, handler)\n this.mqttHandlers.push(h)\n return h\n } else {\n return null\n }\n }\n\n // Subscribe to topic\n public subscribe(topic: string, handler?: (msg: IMessage) => void, qos: number = Constants.DefaultQos): void {\n this.subscribeCore(topic, handler, qos)\n }\n\n // Subscribe to one update on the topic. Returns function that waits for the topic to be updated.\n public awaitUpdate(topic: string, qos: number = Constants.DefaultQos): () => IMessage {\n let res: IMessage = null\n const evid = control.allocateNotifyEvent()\n const h = this.subscribeCore(topic, msg => {\n res = msg\n control.raiseEvent(DAL.DEVICE_ID_NOTIFY, evid)\n }, qos)\n h.status = HandlerStatus.Once\n return () => {\n while (res == null) {\n control.waitForEvent(DAL.DEVICE_ID_NOTIFY, evid)\n }\n return res\n }\n }\n\n private send(data: Buffer): void {\n if (this.sct) {\n this.trace(\"send: \" + data[0] + \" / \" + data.length + \" bytes\")\n // this.log(\"send: \" + data[0] + \" / \" + data.length + \" bytes: \" + data.toHex())\n this.sct.send(data);\n }\n }\n\n private handleMessage(data: Buffer) {\n if (this.buf)\n data = this.buf.concat(data)\n this.buf = data\n if (data.length < 2)\n return\n let len = data[1]\n let payloadOff = 2\n if (len & 0x80) {\n if (data.length < 3)\n return\n if (data[2] & 0x80) {\n this.emit('error', `too large packet.`);\n this.buf = null\n return\n }\n len = (data[2] << 7) | (len & 0x7f)\n payloadOff++\n }\n\n const payloadEnd = payloadOff + len\n if (data.length < payloadEnd)\n return // wait for the rest of data\n\n this.buf = null\n\n const cmd = data[0]\n const controlPacketType: ControlPacketType = cmd >> 4;\n // this.emit('debug', `Rcvd: ${controlPacketType}: '${data}'.`);\n\n const payload = data.slice(payloadOff, payloadEnd - payloadOff)\n\n switch (controlPacketType) {\n case ControlPacketType.ConnAck:\n const returnCode: number = payload[1];\n if (returnCode === ConnectReturnCode.Accepted) {\n this.log('MQTT connection accepted.');\n this.emit('connected');\n this.status = Status.Connected;\n this.piId = setInterval(() => this.ping(), Constants.PingInterval * 1000);\n for (const sub of this.subs)\n this.send1(sub);\n } else {\n const connectionError: string = Client.describe(returnCode);\n this.log('MQTT connection error: ' + connectionError);\n this.emit('error', connectionError);\n this.disconnect()\n }\n break;\n case ControlPacketType.Publish:\n const message: IMessage = Protocol.parsePublish(cmd, payload);\n this.trace(`incoming: ${message.topic}`)\n let handled = false\n let cleanup = false\n if (this.mqttHandlers) {\n for (let h of this.mqttHandlers)\n if (message.topic.slice(0, h.topic.length) == h.topic) {\n h.handler(message)\n handled = true\n if (h.status == HandlerStatus.Once) {\n h.status = HandlerStatus.ToRemove\n cleanup = true\n }\n }\n if (cleanup)\n this.mqttHandlers = this.mqttHandlers.filter(h => h.status != HandlerStatus.ToRemove)\n }\n if (!handled)\n this.emit('receive', message);\n if (message.qos > 0) {\n setTimeout(() => {\n this.send1(Protocol.createPubAck(message.pid || 0));\n }, 0);\n }\n break;\n case ControlPacketType.PingResp:\n case ControlPacketType.PubAck:\n case ControlPacketType.SubAck:\n break;\n default:\n this.emit('error', `MQTT unexpected packet type: ${controlPacketType}.`);\n }\n\n if (data.length > payloadEnd)\n this.handleMessage(data.slice(payloadEnd))\n }\n\n private send1(msg: Buffer) {\n if (this.canSend()) {\n this.send(msg)\n this.doneSending()\n }\n }\n\n private ping() {\n this.send1(Protocol.createPingReq());\n this.emit('debug', 'Sent: Ping request.');\n }\n }\n}",
2004
- "pxt.json": "{\n \"name\": \"mqtt\",\n \"description\": \"MQTT for MakeCode - beta\",\n \"dependencies\": {\n \"core\": \"*\",\n \"net\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"mqtt.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true,\n \"tests\": [\n \"test.ts\"\n ]\n}\n"
2004
+ "pxt.json": "{\n \"name\": \"mqtt\",\n \"description\": \"MQTT for MakeCode - beta\",\n \"dependencies\": {\n \"core\": \"*\",\n \"net\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"mqtt.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true,\n \"tests\": [\n \"test.ts\"\n ]\n}\n"
2005
2005
  },
2006
2006
  "multiplayer": {
2007
2007
  "README.md": "# Multplayer\n\nAdditional blocks for multiplayer. For networked and same-screen alike.\n\n",
@@ -2009,7 +2009,7 @@ var pxtTargetBundle = {
2009
2009
  "images.ts": "namespace mp {\n export function _indicatorForPlayer(player: number, direction: number) {\n switch (direction) {\n case CollisionDirection.Top:\n switch (player) {\n case 1:\n return img`\n . . f f f f f f f f f f f f f . .\n . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f .\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f\n f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f\n f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f\n f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f\n f 2 2 1 1 2 2 2 2 2 2 1 1 2 2 2 f\n f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f\n f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f .\n . . f f f f f 2 2 2 f f f f f . .\n . . . . . . . f 2 f . . . . . . .\n . . . . . . . . f . . . . . . . .\n `;\n case 2:\n return img`\n . . f f f f f f f f f f f f f . .\n . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f .\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f\n f 8 8 1 1 8 1 1 8 1 1 8 1 1 8 8 f\n f 8 8 1 1 8 1 1 8 8 8 8 1 1 8 8 f\n f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 8 8 8 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f .\n . . f f f f f 8 8 8 f f f f f . .\n . . . . . . . f 8 f . . . . . . .\n . . . . . . . . f . . . . . . . .\n `;\n case 3:\n return img`\n . . f f f f f f f f f f f f f . .\n . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f .\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n f 4 4 1 1 1 1 4 4 4 1 1 1 4 4 4 f\n f 4 4 1 1 4 1 1 4 1 1 4 1 1 4 4 f\n f 4 4 1 1 4 1 1 4 4 4 4 1 1 4 4 f\n f 4 4 1 1 1 1 4 4 4 4 1 1 1 4 4 f\n f 4 4 1 1 4 4 4 4 4 4 4 1 1 4 4 f\n f 4 4 1 1 4 4 4 4 1 1 4 1 1 4 4 f\n f 4 4 1 1 4 4 4 4 4 1 1 1 4 4 4 f\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f .\n . . f f f f f 4 4 4 f f f f f . .\n . . . . . . . f 4 f . . . . . . .\n . . . . . . . . f . . . . . . . .\n `;\n case 4:\n return img`\n . . f f f f f f f f f f f f f . .\n . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f .\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n f 6 6 1 1 1 1 6 6 1 1 6 1 1 6 6 f\n f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f\n f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f\n f 6 6 1 1 1 1 6 6 1 1 1 1 1 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f .\n . . f f f f f 6 6 6 f f f f f . .\n . . . . . . . f 6 f . . . . . . .\n . . . . . . . . f . . . . . . . .\n `;\n }\n\n case CollisionDirection.Bottom:\n switch (player) {\n case 1:\n return img`\n . . . . . . . . f . . . . . . . .\n . . . . . . . f 2 f . . . . . . .\n . . f f f f f 2 2 2 f f f f f . .\n . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f .\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f\n f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f\n f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f\n f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f\n f 2 2 1 1 2 2 2 2 2 2 1 1 2 2 2 f\n f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f\n f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f .\n . . f f f f f f f f f f f f f . .\n `;\n case 2:\n return img`\n . . . . . . . . f . . . . . . . .\n . . . . . . . f 8 f . . . . . . .\n . . f f f f f 8 8 8 f f f f f . .\n . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f .\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f\n f 8 8 1 1 8 1 1 8 1 1 8 1 1 8 8 f\n f 8 8 1 1 8 1 1 8 8 8 8 1 1 8 8 f\n f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 8 8 8 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f .\n . . f f f f f f f f f f f f f . .\n `;\n case 3:\n return img`\n . . . . . . . . f . . . . . . . .\n . . . . . . . f 4 f . . . . . . .\n . . f f f f f 4 4 4 f f f f f . .\n . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f .\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n f 4 4 1 1 1 1 4 4 4 1 1 1 4 4 4 f\n f 4 4 1 1 4 1 1 4 1 1 4 1 1 4 4 f\n f 4 4 1 1 4 1 1 4 4 4 4 1 1 4 4 f\n f 4 4 1 1 1 1 4 4 4 4 1 1 1 4 4 f\n f 4 4 1 1 4 4 4 4 4 4 4 1 1 4 4 f\n f 4 4 1 1 4 4 4 4 1 1 4 1 1 4 4 f\n f 4 4 1 1 4 4 4 4 4 1 1 1 4 4 4 f\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f .\n . . f f f f f f f f f f f f f . .\n `;\n case 4:\n return img`\n . . . . . . . . f . . . . . . . .\n . . . . . . . f 6 f . . . . . . .\n . . f f f f f 6 6 6 f f f f f . .\n . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f .\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n f 6 6 1 1 1 1 6 6 1 1 6 1 1 6 6 f\n f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f\n f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f\n f 6 6 1 1 1 1 6 6 1 1 1 1 1 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f .\n . . f f f f f f f f f f f f f . .\n `;\n }\n\n case CollisionDirection.Left:\n switch (player) {\n case 1:\n return img`\n . . f f f f f f f f f f f f f . . . .\n . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f . . .\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f . .\n f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f . .\n f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f . .\n f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 2 f .\n f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 2 2 f\n f 2 2 1 1 2 2 2 2 2 2 1 1 2 2 2 2 f .\n f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f . .\n f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f . .\n f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f . .\n . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f . . .\n . . f f f f f f f f f f f f f . . . .\n `;\n case 2:\n return img`\n . . f f f f f f f f f f f f f . . . .\n . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f . . .\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f . .\n f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f . .\n f 8 8 1 1 8 1 1 8 1 1 8 1 1 8 8 f . .\n f 8 8 1 1 8 1 1 8 8 8 8 1 1 8 8 8 f .\n f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 8 8 f\n f 8 8 1 1 8 8 8 8 1 1 8 8 8 8 8 8 f .\n f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f . .\n f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f . .\n f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f . .\n . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f . . .\n . . f f f f f f f f f f f f f . . . .\n `;\n case 3:\n return img`\n . . f f f f f f f f f f f f f . . . .\n . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f . . .\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f . .\n f 4 4 1 1 1 1 4 4 4 1 1 1 4 4 4 f . .\n f 4 4 1 1 4 1 1 4 1 1 4 1 1 4 4 f . .\n f 4 4 1 1 4 1 1 4 4 4 4 1 1 4 4 4 f .\n f 4 4 1 1 1 1 4 4 4 4 1 1 1 4 4 4 4 f\n f 4 4 1 1 4 4 4 4 4 4 4 1 1 4 4 4 f .\n f 4 4 1 1 4 4 4 4 1 1 4 1 1 4 4 f . .\n f 4 4 1 1 4 4 4 4 4 1 1 1 4 4 4 f . .\n f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f . .\n . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f . . .\n . . f f f f f f f f f f f f f . . . .\n `;\n case 4:\n return img`\n . . f f f f f f f f f f f f f . . . .\n . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f . . .\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f . .\n f 6 6 1 1 1 1 6 6 1 1 6 1 1 6 6 f . .\n f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f . .\n f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 6 f .\n f 6 6 1 1 1 1 6 6 1 1 1 1 1 6 6 6 6 f\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 6 f .\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f . .\n f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f . .\n f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f . .\n . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f . . .\n . . f f f f f f f f f f f f f . . . .\n `;\n }\n\n case CollisionDirection.Right:\n switch (player) {\n case 1:\n return img`\n . . . . f f f f f f f f f f f f f . .\n . . . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f .\n . . f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n . . f 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f\n . . f 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f\n . f 2 2 2 1 1 2 1 1 2 2 1 1 1 2 2 2 f\n f 2 2 2 2 1 1 1 1 2 2 2 2 1 1 2 2 2 f\n . f 2 2 2 1 1 2 2 2 2 2 2 1 1 2 2 2 f\n . . f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f\n . . f 2 2 1 1 2 2 2 2 2 1 1 1 1 2 2 f\n . . f 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 f\n . . . f 2 2 2 2 2 2 2 2 2 2 2 2 2 f .\n . . . . f f f f f f f f f f f f f . .\n `;\n case 2:\n return img`\n . . . . f f f f f f f f f f f f f . .\n . . . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f .\n . . f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n . . f 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f\n . . f 8 8 1 1 8 1 1 8 1 1 8 1 1 8 8 f\n . f 8 8 8 1 1 8 1 1 8 8 8 8 1 1 8 8 f\n f 8 8 8 8 1 1 1 1 8 8 8 1 1 1 8 8 8 f\n . f 8 8 8 1 1 8 8 8 8 1 1 8 8 8 8 8 f\n . . f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f\n . . f 8 8 1 1 8 8 8 8 1 1 1 1 1 8 8 f\n . . f 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 f\n . . . f 8 8 8 8 8 8 8 8 8 8 8 8 8 f .\n . . . . f f f f f f f f f f f f f . .\n `;\n case 3:\n return img`\n . . . . f f f f f f f f f f f f f . .\n . . . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f .\n . . f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n . . f 4 4 1 1 1 1 4 4 4 1 1 1 4 4 4 f\n . . f 4 4 1 1 4 1 1 4 1 1 4 1 1 4 4 f\n . f 4 4 4 1 1 4 1 1 4 4 4 4 1 1 4 4 f\n f 4 4 4 4 1 1 1 1 4 4 4 4 1 1 1 4 4 f\n . f 4 4 4 1 1 4 4 4 4 4 4 4 1 1 4 4 f\n . . f 4 4 1 1 4 4 4 4 1 1 4 1 1 4 4 f\n . . f 4 4 1 1 4 4 4 4 4 1 1 1 4 4 4 f\n . . f 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 f\n . . . f 4 4 4 4 4 4 4 4 4 4 4 4 4 f .\n . . . . f f f f f f f f f f f f f . .\n `;\n case 4:\n return img`\n . . . . f f f f f f f f f f f f f . .\n . . . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f .\n . . f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n . . f 6 6 1 1 1 1 6 6 1 1 6 1 1 6 6 f\n . . f 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f\n . f 6 6 6 1 1 6 1 1 6 1 1 6 1 1 6 6 f\n f 6 6 6 6 1 1 1 1 6 6 1 1 1 1 1 6 6 f\n . f 6 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n . . f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n . . f 6 6 1 1 6 6 6 6 6 6 6 1 1 6 6 f\n . . f 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 f\n . . . f 6 6 6 6 6 6 6 6 6 6 6 6 6 f .\n . . . . f f f f f f f f f f f f f . .\n `;\n }\n }\n\n return undefined;\n }\n}\n",
2010
2010
  "ns.ts": "//% color=\"#207a77\" weight=96 icon=\"\\uf0c0\"\n//% blockGap=8\n//% block=\"Multiplayer\"\n//% groups='[\"Sprites\", \"Controller\", \"Info\", \"Game\", \"Utility\"]'\nnamespace mp {\n}\n",
2011
2011
  "player.ts": "namespace mp {\n const MAX_PLAYERS = 4;\n\n export enum PlayerNumber {\n //% block=\"1\"\n One = 1,\n //% block=\"2\"\n Two = 2,\n //% block=\"3\"\n Three = 3,\n //% block=\"4\"\n Four = 4\n }\n\n export enum PlayerProperty {\n //% block=\"index\"\n Index = 1,\n //% block=\"number\"\n Number = 2\n }\n\n export enum MultiplayerButton {\n //% block=\"A\"\n A,\n //% block=\"B\"\n B,\n //% block=\"up\"\n Up,\n //% block=\"right\"\n Right,\n //% block=\"down\"\n Down,\n //% block=\"left\"\n Left\n }\n\n class ButtonHandler {\n constructor(public button: MultiplayerButton, public event: ControllerButtonEvent, public handler: (player: Player) => void) {\n }\n }\n\n class ControllerEventHandler {\n constructor(public event: ControllerEvent, public handler: (player: Player) => void) {\n }\n }\n\n class ScoreHandler {\n constructor(public target: number, public handler: (player: Player) => void) {\n }\n }\n\n /**\n * A player in the game\n */\n export class Player {\n _sprite: Sprite;\n _state: number[];\n _index: number;\n _data: any;\n _mwb: boolean;\n _vx: number;\n _vy: number;\n\n constructor(index: number) {\n this._index = index;\n }\n\n get index(): number {\n return this._index;\n }\n\n get number(): number {\n return this._index + 1;\n }\n\n get data(): any {\n if (!this._data) this._data = {};\n return this._data;\n }\n\n set data(value: any) {\n this._data = value;\n }\n\n getProperty(prop: PlayerProperty): number {\n switch (prop) {\n case PlayerProperty.Index: return this.index;\n case PlayerProperty.Number: return this.number;\n default: return 0;\n }\n }\n\n getSprite(): Sprite {\n return this._sprite;\n }\n\n setSprite(sprite: Sprite) {\n if (sprite && sprite.image) {\n // Passing 'implicit' flag so we don't override icons that\n // user has explicitly defined.\n mp.postPresenceIcon(\n this.number,\n sprite.image,\n /** implicit **/ true\n );\n } else {\n // Passing 'implicit' flag so we don't override icons that\n // user has explicitly defined.\n mp.postPresenceIcon(\n this.number,\n undefined,\n /** implicit **/ true\n );\n\n }\n\n if (this._sprite && this._mwb) {\n this._getController().stopControllingSprite(this._sprite);\n }\n\n this._sprite = sprite;\n\n if (this._sprite && this._mwb) {\n this._getController().moveSprite(this._sprite, this._vx, this._vy);\n }\n }\n\n moveWithButtons(vx?: number, vy?: number) {\n this._mwb = true;\n this._vx = vx;\n this._vy = vy;\n this._getController().moveSprite(this.getSprite(), vx, vy);\n }\n\n getState(key: number): number {\n if (key === MultiplayerState.score) {\n return this._getInfo().score();\n }\n if (key === MultiplayerState.life) {\n return this._getInfo().life();\n }\n return this._getState(key);\n }\n\n setState(key: number, val: number) {\n if (key === MultiplayerState.score) {\n this._getInfo().setScore(val);\n }\n if (key === MultiplayerState.life) {\n this._getInfo().setLife(val);\n }\n this._setState(key, val);\n }\n\n _setState(key: number, val: number) {\n this._ensureState(key);\n if (this._state.length > key)\n this._state[key] = val;\n }\n\n _getState(key: number): number {\n this._ensureState(key);\n return (this._state.length > key) ? this._state[key] : 0;\n }\n\n _ensureState(key: number) {\n if (!this._state) this._state = [];\n if (key < 0 || key > 255) return;\n while (this._state.length < key) this._state.push(0);\n }\n\n _getInfo(): info.PlayerInfo {\n switch (this._index) {\n case 0: return info.player1;\n case 1: return info.player2;\n case 2: return info.player3;\n case 3: return info.player4;\n default: return undefined;\n }\n }\n\n _getController(): controller.Controller {\n switch (this._index) {\n case 0: return controller.player1 as any;\n case 1: return controller.player2;\n case 2: return controller.player3;\n case 3: return controller.player4;\n }\n return undefined;\n }\n }\n\n class MPState {\n players: Player[];\n buttonHandlers: ButtonHandler[];\n controllerEventHandlers: ControllerEventHandler[];\n scoreHandlers: ScoreHandler[];\n lifeZeroHandler: (player: Player) => void;\n indicatorsVisible: boolean;\n indicatorRenderable: scene.Renderable;\n\n constructor() {\n this.players = [];\n for (let i = 0; i < MAX_PLAYERS; ++i)\n this.players.push(new Player(i));\n this.buttonHandlers = [];\n this.controllerEventHandlers = [];\n this.scoreHandlers = [];\n this.indicatorsVisible = false;\n }\n\n onButtonEvent(button: MultiplayerButton, event: ControllerButtonEvent, handler: (player: Player) => void) {\n const existing = this.getButtonHandler(button, event);\n\n if (existing) {\n existing.handler = handler;\n return;\n }\n\n this.buttonHandlers.push(new ButtonHandler(button, event, handler));\n\n for (const player of this.players) {\n getButton(player._getController(), button).onEvent(event, () => {\n this.getButtonHandler(button, event).handler(player);\n })\n }\n }\n\n onControllerEvent(event: ControllerEvent, handler: (player: Player) => void) {\n const existing = this.getControllerEventHandler(event);\n\n if (existing) {\n existing.handler = handler;\n return;\n }\n\n this.controllerEventHandlers.push(new ControllerEventHandler(event, handler));\n\n for (const player of this.players) {\n player._getController().onEvent(event, () => {\n this.getControllerEventHandler(event).handler(player);\n })\n }\n }\n\n onReachedScore(score: number, handler: (player: Player) => void) {\n const existing = this.getScoreHandler(score);\n\n if (existing) {\n existing.handler = handler;\n return;\n }\n\n this.scoreHandlers.push(new ScoreHandler(score, handler));\n\n for (const player of this.players) {\n player._getInfo().onScore(score, () => {\n this.getScoreHandler(score).handler(player);\n })\n }\n }\n\n onLifeZero(handler: (player: Player) => void) {\n if (!this.lifeZeroHandler) {\n for (const player of this.players) {\n player._getInfo().onLifeZero(() => {\n this.lifeZeroHandler(player);\n })\n }\n }\n this.lifeZeroHandler = handler;\n }\n\n setPlayerIndicatorsVisible(visible: boolean) {\n this.indicatorsVisible = visible;\n\n if (visible && !this.indicatorRenderable) {\n this.indicatorRenderable = scene.createRenderable(99, (target, camera) => {\n if (this.indicatorsVisible) this.drawIndicators(target, camera);\n })\n }\n }\n\n getButtonHandler(button: MultiplayerButton, event: ControllerButtonEvent) {\n for (const handler of this.buttonHandlers) {\n if (handler.button === button && handler.event === event) return handler;\n }\n return undefined;\n }\n\n getControllerEventHandler(event: ControllerEvent) {\n for (const handler of this.controllerEventHandlers) {\n if (handler.event === event) return handler;\n }\n return undefined;\n }\n\n\n getScoreHandler(score: number) {\n for (const handler of this.scoreHandlers) {\n if (handler.target === score) return handler;\n }\n return undefined;\n }\n\n drawIndicators(target: Image, camera: scene.Camera) {\n for (const player of this.players) {\n const sprite = player.getSprite();\n\n if (!sprite || sprite.flags & (sprites.Flag.Destroyed | sprites.Flag.Invisible)) {\n continue;\n }\n\n let top = Fx.toInt(sprite._hitbox.top)\n let bottom = Fx.toInt(sprite._hitbox.bottom)\n let left = Fx.toInt(sprite._hitbox.left)\n let right = Fx.toInt(sprite._hitbox.right)\n\n if (!(sprite.flags & sprites.Flag.RelativeToCamera)) {\n top -= camera.drawOffsetY;\n bottom -= camera.drawOffsetY;\n left -= camera.drawOffsetX;\n right -= camera.drawOffsetX;\n }\n\n if (left < 0) {\n const indicator = _indicatorForPlayer(player.number, CollisionDirection.Right);\n target.drawTransparentImage(\n indicator,\n Math.max(right + 2, 0),\n Math.min(\n Math.max(\n (top + ((bottom - top) >> 1) - (indicator.height >> 1)),\n 0\n ),\n screen.height - indicator.height\n )\n )\n }\n else if (right > 160) {\n const indicator = _indicatorForPlayer(player.number, CollisionDirection.Left);\n target.drawTransparentImage(\n indicator,\n Math.min(left - indicator.width - 2, screen.width - indicator.width),\n Math.min(\n Math.max(\n (top + ((bottom - top) >> 1) - (indicator.height >> 1)),\n 0\n ),\n screen.height - indicator.height\n )\n )\n }\n else if (top < 18) {\n const indicator = _indicatorForPlayer(player.number, CollisionDirection.Bottom);\n target.drawTransparentImage(\n indicator,\n (left + ((right - left) >> 1) - (indicator.width >> 1)),\n Math.max(bottom + 2, 0)\n )\n }\n else {\n const indicator = _indicatorForPlayer(player.number, CollisionDirection.Top);\n target.drawTransparentImage(\n indicator,\n (left + ((right - left) >> 1) - (indicator.width >> 1)),\n Math.min(top - indicator.height - 2, screen.height - indicator.height)\n )\n }\n }\n }\n }\n\n let stateStack: MPState[];\n\n function init() {\n if (stateStack) return;\n stateStack = [new MPState()];\n game.addScenePushHandler(() => {\n stateStack.push(new MPState());\n });\n game.addScenePopHandler(() => {\n stateStack.pop();\n if (stateStack.length === 0) stateStack.push(new MPState());\n });\n }\n\n export function _mpstate() {\n init();\n return stateStack[stateStack.length - 1];\n }\n\n function getButton(ctrl: controller.Controller, button: MultiplayerButton) {\n switch (button) {\n case MultiplayerButton.A: return ctrl.A;\n case MultiplayerButton.B: return ctrl.B;\n case MultiplayerButton.Up: return ctrl.up;\n case MultiplayerButton.Right: return ctrl.right;\n case MultiplayerButton.Down: return ctrl.down;\n case MultiplayerButton.Left: return ctrl.left;\n }\n }\n\n /**\n * Gets the sprite of the player\n * @param player The player to get the sprite of\n * @returns The sprite of the player, or undefined if the player has no assigned sprite\n */\n //% blockId=mp_getPlayerSprite\n //% block=\"$player sprite\"\n //% player.shadow=mp_playerSelector\n //% group=Sprites\n //% weight=100\n //% blockGap=8\n //% help=multiplayer/get-player-sprite\n //% parts=\"multiplayer\"\n export function getPlayerSprite(player: Player): Sprite {\n if (!player) return undefined;\n return player.getSprite();\n }\n\n /**\n * Sets the sprite of the player\n * @param player The player to set the sprite for\n * @param sprite The sprite to set\n */\n //% blockId=mp_setPlayerSprite\n //% block=\"set $player sprite to $sprite\"\n //% player.shadow=mp_playerSelector\n //% sprite.shadow=spritescreate\n //% group=Sprites\n //% weight=100\n //% blockGap=8\n //% help=multiplayer/set-player-sprite\n //% parts=\"multiplayer\"\n export function setPlayerSprite(player: Player, sprite: Sprite) {\n if (!player) return;\n player.setSprite(sprite);\n }\n\n /**\n * Control a player's sprite with directional buttons\n * @param player The player to control\n * @param vx The horizontal velocity of the sprite (optional)\n * @param vy The vertical velocity of the sprite (optional)\n */\n //% blockId=mp_moveWithButtons\n //% block=\"move $player with buttons||vx $vx vy $vy\"\n //% player.shadow=mp_playerSelector\n //% vx.defl=100\n //% vy.defl=100\n //% vx.shadow=\"spriteSpeedPicker\"\n //% vy.shadow=\"spriteSpeedPicker\"\n //% expandableArgumentMode=\"toggle\"\n //% inlineInputMode=inline\n //% group=Controller\n //% weight=100\n //% blockGap=8\n //% help=controller/move-sprite\n //% parts=\"multiplayer\"\n export function moveWithButtons(player: Player, vx?: number, vy?: number) {\n if (!player) return;\n player.moveWithButtons(vx, vy);\n }\n\n /**\n * Runs code when a button on any controller is pressed, released, or held\n * @param button The button to listen for\n * @param event The event to listen for (pressed, released, or held)\n * @param handler The code to run when the button is pressed, released, or held\n */\n //% blockId=mp_onButtonEvent\n //% block=\"on $button button $event for $player\"\n //% draggableParameters=reporter\n //% group=Controller\n //% weight=90\n //% blockGap=8\n //% help=controller/on-button-event\n //% parts=\"multiplayer\"\n export function onButtonEvent(button: MultiplayerButton, event: ControllerButtonEvent, handler: (player: Player) => void) {\n _mpstate().onButtonEvent(button, event, handler);\n }\n\n /**\n * Queries the state of a button on a controller\n * @param player The player to query\n * @param button The button to query\n * @returns true if the button is pressed\n */\n //% blockId=mp_isButtonPressed\n //% block=\"is $player $button button pressed\"\n //% player.shadow=mp_playerSelector\n //% group=Controller\n //% weight=80\n //% blockGap=8\n //% help=controller/button/is-pressed\n //% parts=\"multiplayer\"\n export function isButtonPressed(player: Player, button: MultiplayerButton): boolean {\n if (!player) return false;\n return getButton(player._getController(), button).isPressed();\n }\n\n /**\n * Runs code when a controller is connected or disconnected\n * @param event The event to listen for (controller connected or disconnected)\n * @param handler Code to run when the event is raised\n */\n //% blockId=mp_onControllerEvent\n //% block=\"on $player $event\"\n //% draggableParameters=reporter\n //% group=Controller\n //% weight=70\n //% blockGap=8\n //% help=controller/on-event\n //% parts=\"multiplayer\"\n export function onControllerEvent(event: ControllerEvent, handler: (player: Player) => void) {\n _mpstate().onControllerEvent(event, handler);\n }\n\n /**\n * Gets the value of the specified player state\n * @param player The player to get the state for\n * @param state The state to get\n * @returns The value of the state\n */\n //% blockId=mp_getPlayerState\n //% block=\"$player $state\"\n //% player.shadow=mp_playerSelector\n //% state.shadow=mp_multiplayerstate\n //% group=Info\n //% weight=100\n //% blockGap=8\n //% help=multiplayer/get-player-state\n //% parts=\"multiplayer\"\n export function getPlayerState(player: Player, state: number): number {\n if (!player) return 0;\n return player.getState(state);\n }\n\n /**\n * Sets the value of the specified player state\n * @param player The player to set the state for\n * @param state The state to set\n * @param value The value to set the state to\n */\n //% blockId=mp_setPlayerState\n //% block=\"set $player $state to $value\"\n //% player.shadow=mp_playerSelector\n //% state.shadow=mp_multiplayerstate\n //% group=Info\n //% weight=90\n //% blockGap=8\n //% help=multiplayer/set-player-state\n //% parts=\"multiplayer\"\n export function setPlayerState(player: Player, state: number, value: number) {\n if (!player) return;\n player.setState(state, value);\n }\n\n /**\n * Changes the value of the specified player state\n * @param player The player to change the state for\n * @param state The state to change\n * @param delta The amount to change the state by\n */\n //% blockId=mp_changePlayerStateBy\n //% block=\"change $player $state by $delta\"\n //% player.shadow=mp_playerSelector\n //% state.shadow=mp_multiplayerstate\n //% delta.defl=1\n //% group=Info\n //% weight=80\n //% blockGap=8\n //% help=multiplayer/change-player-state-by\n //% parts=\"multiplayer\"\n export function changePlayerStateBy(player: Player, state: number, delta: number) {\n if (!player) return;\n player.setState(state, player.getState(state) + delta);\n }\n\n /**\n * Gets a property of the player\n * @param player The player to get the property of\n * @param prop The property to get\n * @returns The value of the property\n */\n //% blockId=mp_getPlayerProperty\n //% block=\"$player $prop\"\n //% player.shadow=mp_playerSelector\n //% group=Info\n //% weight=100\n //% blockGap=8\n //% help=multiplayer/get-player-property\n //% parts=\"multiplayer\"\n export function getPlayerProperty(player: Player, prop: PlayerProperty): number {\n if (!player) return 0;\n return player.getProperty(prop);\n }\n\n /**\n * Runs code once each time a player's score reaches a given value.\n * @param score The score to check for, eg: 100\n * @param handler The code to run when the score is reached\n */\n //% blockId=mp_onScore\n //% block=\"on score $score for $player\"\n //% score.defl=100\n //% draggableParameters=reporter\n //% group=Info\n //% weight=70\n //% blockGap=8\n //% help=info/on-score\n //% parts=\"multiplayer\"\n export function onScore(score: number, handler: (player: Player) => void) {\n _mpstate().onReachedScore(score, handler);\n }\n\n /**\n * Runs code when a player's number of lives reaches zero\n * @param handler The code to run when the lives reach zero\n */\n //% blockId=mp_onLifeZero\n //% block=\"on life zero for $player\"\n //% draggableParameters=reporter\n //% group=Info\n //% weight=60\n //% blockGap=8\n //% help=info/on-life-zero\n //% parts=\"multiplayer\"\n export function onLifeZero(handler: (player: Player) => void) {\n _mpstate().onLifeZero(handler);\n }\n\n //% blockId=mp_gameOverPlayerWin\n //% block=\"game over $player wins\"\n //% player.shadow=mp_playerSelector\n //% group=Game\n //% weight=100\n //% blockGap=8\n //% help=multiplayer/game-over-player-win\n //% parts=\"multiplayer\"\n export function gameOverPlayerWin(player: Player) {\n if (!player) return;\n game.gameOverPlayerWin(player.number);\n }\n\n /**\n * Gets the player by number\n * @param number The one-based number of the player\n * @returns Player, or undefined if not found\n */\n //% blockId=mp_getPlayerByNumber\n //% block=\"player $number\"\n //% number.shadow=variables_get\n //% number.defl=number\n //% group=Utility\n //% weight=80\n //% blockGap=8\n //% help=multiplayer/get-player-by-number\n //% parts=\"multiplayer\"\n export function getPlayerByNumber(number: number): Player {\n const index = number - 1;\n return getPlayerByIndex(index);\n }\n\n /**\n * Gets the player by index\n * @param index The zero-based index of the player\n * @returns Player, or undefined if not found\n */\n //% blockId=mp_getPlayerByIndex\n //% block=\"player at $index\"\n //% index.shadow=variables_get\n //% index.defl=index\n //% group=Utility\n //% weight=80\n //% blockGap=8\n //% help=multiplayer/get-player-by-index\n //% parts=\"multiplayer\"\n export function getPlayerByIndex(index: number): Player {\n if (index < 0 || index >= MAX_PLAYERS) return undefined;\n return _mpstate().players[index];\n }\n\n /**\n * Selects one of the players by number\n * @param number The player number\n * @returns The player\n */\n //% blockId=mp_playerSelector\n //% block=\"player $number\"\n //% group=Utility\n //% weight=80\n //% blockGap=8\n //% help=multiplayer/player-selector\n //% parts=\"multiplayer\"\n export function playerSelector(number: PlayerNumber): Player {\n const index = number - 1;\n return getPlayerByIndex(index);\n }\n\n /**\n * Gets the player the sprite is assigned to\n * @param sprite the sprite\n * @returns Player, or undefined if not found\n */\n //% blockId=mp_getPlayerBySprite\n //% block=\"$sprite player\"\n //% sprite.shadow=variables_get\n //% sprite.defl=mySprite\n //% group=Sprites\n //% weight=90\n //% blockGap=8\n //% help=multiplayer/get-player-by-sprite\n //% parts=\"multiplayer\"\n export function getPlayerBySprite(sprite: Sprite): Player {\n for (const player of _mpstate().players) {\n if (player.getSprite() === sprite) return player;\n }\n return undefined;\n }\n\n /**\n * Turns player indicators on or off\n * @param visible indicator visibility\n */\n //% blockId=mp_setPlayerIndicatorsVisible\n //% block=\"set player indicators $visible\"\n //% visible.shadow=toggleOnOff\n //% visible.defl=true\n //% group=Utility\n //% weight=100\n //% blockGap=8\n //% help=multiplayer/set-player-indicators-visible\n //% parts=\"multiplayer\"\n export function setPlayerIndicatorsVisible(visible: boolean) {\n _mpstate().setPlayerIndicatorsVisible(visible);\n }\n}\n",
2012
- "pxt.json": "{\n \"name\": \"multiplayer\",\n \"description\": \"Additional blocks for building multiplayer games\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"ns.ts\",\n \"fieldEditors.ts\",\n \"images.ts\",\n \"player.ts\",\n \"stateKind.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 80,\n \"icon\": \"/static/libs/multiplayer.png\"\n}\n",
2012
+ "pxt.json": "{\n \"name\": \"multiplayer\",\n \"description\": \"Additional blocks for building multiplayer games\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"ns.ts\",\n \"fieldEditors.ts\",\n \"images.ts\",\n \"player.ts\",\n \"stateKind.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 80,\n \"icon\": \"/static/libs/multiplayer.png\"\n}\n",
2013
2013
  "stateKind.ts": "namespace MultiplayerState {\n let nextKind: number;\n\n export function create() {\n if (nextKind === undefined) nextKind = 0;\n return nextKind++;\n }\n\n //% isKind\n export const score = create();\n\n //% isKind\n export const life = create();\n}\n",
2014
2014
  "targetoverrides.ts": "// TODO any platform specific overrides",
2015
2015
  "test.ts": ""
@@ -2020,41 +2020,41 @@ var pxtTargetBundle = {
2020
2020
  "controllersocket.ts": "namespace net {\n\n export const SOCK_STREAM = 1\n export const AF_INET = 2\n export const MAX_PACKET = 4000\n export const TCP_MODE = 0\n export const UDP_MODE = 1\n export const TLS_MODE = 2\n\n export class ControllerSocket implements net.Socket {\n _buffer: Buffer;\n _socknum: number;\n _timeout: number;\n _closed: boolean;\n _openHandler: () => void;\n _closeHandler: () => void;\n _errorHandler: (msg: string) => void;\n _messageHandler: (data: Buffer) => void;\n\n /** A simplified implementation of the Python 'socket' class, for connecting\n through an interface to a remote device\n */\n constructor(private controller: Controller, private host: string | Buffer, private port: number, private conntype: number = null) {\n if (this.conntype === null) {\n this.conntype = net.TCP_MODE\n }\n this._buffer = hex``\n this._socknum = this.controller.socket()\n this.setTimeout(0)\n }\n\n /** Connect the socket to the 'address' (which can be 32bit packed IP or\n a hostname string). 'conntype' is an extra that may indicate SSL or not,\n depending on the underlying interface\n*/\n public connect() {\n if (!this.controller.socketConnect(this._socknum, this.host, this.port, this.conntype)) {\n this.error(`failed to connect to ${this.host}`)\n return;\n }\n\n this._buffer = hex``\n\n if (this._openHandler)\n this._openHandler();\n }\n\n /** Send some data to the socket */\n public send(data: string | Buffer) {\n //console.log(\"sock wr: \" + data)\n this.controller.socketWrite(this._socknum, net.dataAsBuffer(data))\n }\n\n private error(msg: string) {\n if (this._errorHandler)\n this._errorHandler(msg)\n }\n\n onOpen(handler: () => void): void {\n this._openHandler = handler;\n }\n onClose(handler: () => void): void {\n this._closeHandler = handler;\n }\n onError(handler: (msg: string) => void): void {\n this._errorHandler = handler;\n }\n\n private flushReadBuffer() {\n while (!this._closed && this._messageHandler) {\n const buf = this.read()\n if (buf.length) {\n this._messageHandler(buf)\n } else {\n break\n }\n }\n }\n\n onMessage(handler: (data: Buffer) => void): void {\n if (this._messageHandler === undefined) {\n const src = this.controller.dataAvailableSrc(this._socknum)\n const value = this.controller.dataAvailableValue(this._socknum)\n if (src > 0 && value > 0) {\n this.flushReadBuffer()\n control.internalOnEvent(src, value, () => this.flushReadBuffer())\n } else {\n control.runInParallel(() => {\n while (!this._closed) {\n this.flushReadBuffer()\n pause(200)\n }\n })\n }\n }\n this._messageHandler = handler || null;\n }\n\n /** Attempt to return as many bytes as we can up to but not including '\\r\\n' */\n public readLine(): string {\n // print(\"Socket readline\")\n let stamp = monotonic()\n while (this._buffer.indexOf(hex`0d0a`) < 0) {\n // there's no line already in there, read some more\n let avail = Math.min(this.controller.socketAvailable(this._socknum), MAX_PACKET)\n if (avail > 0) {\n this._buffer = this._buffer.concat(this.controller.socketRead(this._socknum, avail))\n } else if (avail < 0 || (this._timeout > 0 && monotonic() - stamp > this._timeout)) {\n // Make sure to close socket so that we don't exhaust sockets.\n this.close()\n throw \"Didn't receive full response, failing out\"\n } else {\n pause(20)\n }\n }\n const pos = this._buffer.indexOf(hex`0d0a`)\n const pref = this._buffer.slice(0, pos)\n this._buffer = this._buffer.slice(pos + 2)\n // print(\"rd: \" + this._buffer.length + \" / \" + pref.length + \" :\" + pref.toString())\n return pref.toString()\n }\n\n /** Read up to 'size' bytes from the socket, this may be buffered internally! If 'size' isn't specified, return everything in the buffer. */\n public read(size: number = 0): Buffer {\n // print(\"Socket read\", size)\n if (size == 0) {\n if (this._buffer.length == 0) {\n let avail = Math.min(this.controller.socketAvailable(this._socknum), MAX_PACKET)\n if (avail > 0)\n this._buffer = this.controller.socketRead(this._socknum, avail)\n if (avail < 0)\n this.close()\n }\n let ret = this._buffer\n this._buffer = hex``\n return ret\n }\n\n let stamp = monotonic()\n let to_read = size - this._buffer.length\n let received = []\n while (to_read > 0) {\n // print(\"Bytes to read:\", to_read)\n let avail = Math.min(this.controller.socketAvailable(this._socknum), MAX_PACKET)\n if (avail > 0) {\n stamp = monotonic()\n let recv = this.controller.socketRead(this._socknum, Math.min(to_read, avail))\n received.push(recv)\n to_read -= recv.length\n } else {\n pause(20)\n }\n\n if (avail < 0 || (this._timeout > 0 && monotonic() - stamp > this._timeout)) {\n break\n }\n\n }\n // print(received)\n received.unshift(this._buffer)\n this._buffer = pins.concatBuffers(received)\n let ret = null\n if (this._buffer.length == size) {\n ret = this._buffer\n this._buffer = hex``\n } else {\n ret = this._buffer.slice(0, size)\n this._buffer = this._buffer.slice(size)\n }\n\n return ret\n }\n\n /** Set the read timeout for sockets, if value is 0 it will block */\n public setTimeout(value: number) {\n this._timeout = value\n }\n\n /** Close the socket, after reading whatever remains */\n public close() {\n this._closed = true;\n this._buffer = hex``\n this.controller.socketClose(this._socknum)\n if (this._closeHandler)\n this._closeHandler();\n }\n }\n}\n",
2021
2021
  "net.ts": "/**\n * Networking, WiFi, web requests\n */\n//% weight=1\n//% advanced=true\n//% icon=\"\\uf1eb\" color=\"#8446cf\"\nnamespace net {\n /**\n * Default priority of net log messages\n **/\n export let logPriority: ConsolePriority = -1;\n export function log(msg: string) {\n console.add(logPriority, \"net:\" + msg);\n }\n export function debug(msg: string) {\n if (logPriority > ConsolePriority.Debug)\n console.add(ConsolePriority.Debug, \"net:\" + msg);\n }\n export function fail(reason: string) {\n net.log(`error: ${reason}`);\n throw reason;\n }\n\n export function monotonic(): number {\n return control.millis() / 1000.0;\n }\n\n export const enum WifiAPFlags {\n HasPassword = 0x1,\n WPS = 0x2,\n HasSecondaryChannelAbove = 0x4,\n HasSecondaryChannelBelow = 0x8,\n IEEE_802_11B = 0x100,\n IEEE_802_11A = 0x200,\n IEEE_802_11G = 0x400,\n IEEE_802_11N = 0x800,\n IEEE_802_11AC = 0x1000,\n IEEE_802_11AX = 0x2000,\n IEEE_802_LongRange = 0x8000,\n }\n\n export class AccessPoint {\n flags: WifiAPFlags\n rssi: number\n bssid: Buffer\n channel: number\n constructor(public ssid: string) { }\n static fromBuffer(buf: Buffer) {\n const name = buf.slice(16)\n let endp = name.length - 1\n while (endp > 0 && name[endp] == 0)\n endp--\n endp++\n const res = new AccessPoint(name.slice(0, endp).toString())\n const [flags, _reserved, rssi, channel] = buf.unpack(\"<IIbB\")\n res.flags = flags\n res.rssi = rssi\n res.channel = channel\n res.bssid = buf.slice(10, 6)\n if (res.bssid.toArray(NumberFormat.UInt16LE).every(x => x == 0))\n res.bssid = null\n return res\n }\n toBuffer() {\n /*\n flags: APFlags\n reserved: u32\n rssi: i8 dB {typical_min = -100, typical_max = -20}\n channel: u8 {typical_min = 1, typical_max = 13}\n bssid: u8[6]\n ssid: string {max_bytes = 33}\n */\n const pref = Buffer.pack(\"<IIbB\", [this.flags, 0, this.rssi, this.channel])\n const bssid = Buffer.create(6)\n if (this.bssid) bssid.write(0, this.bssid)\n return pref.concat(bssid).concat(Buffer.fromUTF8(this.ssid))\n }\n }\n\n export interface Socket {\n connect(): void;\n send(data: string | Buffer): void;\n read(contentLength: number): Buffer;\n close(): void;\n onOpen(handler: () => void): void;\n onClose(handler: () => void): void;\n onError(handler: (msg: string) => void): void;\n onMessage(handler: (data: Buffer) => void): void;\n setTimeout(millis: number): void;\n readLine(): string;\n }\n\n export class Net {\n private _controller: Controller;\n constructor(private factory: () => Controller) {\n Net.instance = this;\n this._controller = undefined; // null failed to initialize\n }\n\n static instance: Net;\n\n get controller(): net.Controller {\n if (this._controller === undefined) {\n net.log(`init controller`)\n this._controller = this.factory();\n if (!this._controller) {\n net.log(`controller not found`)\n this._controller = null;\n }\n }\n return this._controller;\n }\n\n /**\n * Scan for APs\n */\n scanNetworks(): net.AccessPoint[] {\n const c = this.controller;\n try {\n return c ? c.scanNetworks() : [];\n } catch (e) {\n console.error(\"\" + e)\n return [];\n }\n }\n\n createSocket(host: string, port: number, secure: boolean): net.Socket {\n const c = this.controller;\n if (!c) return undefined;\n const socket = new net.ControllerSocket(c, host, port, secure ? net.TLS_MODE : net.TCP_MODE);\n return socket;\n }\n\n hostByName(host: string): string {\n const c = this.controller;\n if (!c) return undefined;\n const b = this.controller.hostbyName(host);\n if (b) return b.toString();\n return undefined;\n }\n }\n\n /**\n * Gets the current Net instance\n */\n export function instance(): Net {\n return net.Net.instance;\n }\n\n const AP_SECRETS_KEY = \"wifi\";\n const AP_PRI_KEY = \"#wifipriority\";\n /**\n * Gets the map of SSID -> password pairs\n */\n export function knownAccessPoints(): StringMap {\n return settings.deviceSecrets.readSecret(AP_SECRETS_KEY) || {};\n }\n\n export function clearAccessPoint(ssid: string) {\n const ap = knownAccessPoints()\n if (ap[ssid] !== undefined) {\n delete ap[ssid]\n settings.deviceSecrets.setSecret(AP_SECRETS_KEY, ap)\n }\n }\n\n export function updateAccessPoint(ssid: string, password: string) {\n const k: StringMap = {};\n k[ssid] = password;\n settings.deviceSecrets.updateSecret(AP_SECRETS_KEY, k);\n }\n\n export function setAccessPointPriority(ssid: string, pri: number) {\n const s = accessPointPriorities()\n if (s[ssid] != pri) {\n s[ssid] = pri\n settings.writeJSON(AP_PRI_KEY, s)\n }\n }\n\n export function accessPointPriorities() {\n return settings.readJSON(AP_PRI_KEY) || {}\n }\n\n export function clearAccessPoints() {\n settings.deviceSecrets.setSecret(AP_SECRETS_KEY, undefined);\n }\n}",
2022
2022
  "netutil.ts": "namespace net {\n export function urlencode(s: string) {\n const buf = Buffer.fromUTF8(s)\n let r = \"\"\n for (let i = 0; i < buf.length; ++i) {\n const c = buf[i]\n if ((48 <= c && c <= 57) ||\n (97 <= (c | 0x20) && (c | 0x20) <= 122) ||\n (c == 45 || c == 46 || c == 95 || c == 126))\n r += String.fromCharCode(c)\n else\n r += \"%\" + buf.slice(i, 1).toHex()\n }\n return r\n }\n\n export function urldecode(s: string) {\n let r = \"\"\n let isUtf8 = false\n for (let i = 0; i < s.length; ++i) {\n const c = s[i]\n if (c == \"%\") {\n const h = s.slice(i + 1, i + 3)\n const chcode = parseInt(h, 16)\n if (!isNaN(chcode)) {\n if (chcode > 127)\n isUtf8 = true\n r += String.fromCharCode(chcode)\n i += 2\n continue\n }\n }\n r += c\n }\n if (isUtf8) {\n const buf = Buffer.create(r.length)\n for (let i = 0; i < buf.length; ++i)\n buf[i] = r.charCodeAt(i)\n return buf.toString()\n } else {\n return r\n }\n }\n}",
2023
- "pxt.json": "{\n \"name\": \"net\",\n \"description\": \"Networking abstractions\",\n \"dependencies\": {\n \"core\": \"*\",\n \"settings\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"controller.ts\",\n \"controllersocket.ts\",\n \"net.ts\",\n \"netutil.ts\",\n \"requests.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2023
+ "pxt.json": "{\n \"name\": \"net\",\n \"description\": \"Networking abstractions\",\n \"dependencies\": {\n \"core\": \"*\",\n \"settings\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"controller.ts\",\n \"controllersocket.ts\",\n \"net.ts\",\n \"netutil.ts\",\n \"requests.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2024
2024
  "requests.ts": "namespace net {\n /**\n * Pings a web site\n * @param dest host name\n * @param ttl \n */\n //% blockId=netping block=\"net ping $dest\"\n export function ping(dest: string, ttl: number = 250): number {\n net.log(`ping ${dest}`);\n const c = net.instance().controller;\n if (!c) return Infinity;\n // don't crash.\n try {\n return c.ping(dest, ttl);\n } catch (e) {\n console.error(\"\" + e)\n return Infinity;\n }\n }\n\n export class Response {\n _cached: Buffer\n status_code: number\n reason: string\n _read_so_far: number\n headers: StringMap;\n\n /** \n * The response from a request, contains all the headers/content \n */\n constructor(private socket: Socket) {\n this._cached = null\n this.status_code = null\n this.reason = null\n this._read_so_far = 0\n this.headers = {}\n }\n\n /** \n * Close, delete and collect the response data \n */\n public close() {\n if (this.socket) {\n this.socket.close()\n this.socket = null\n }\n this._cached = null\n }\n\n /** \n * The HTTP content direct from the socket, as bytes \n */\n get content() {\n // print(\"Content length:\", content_length)\n if (this._cached === null && this.socket) {\n const content_length = parseInt(this.headers[\"content-length\"]) || 0\n this._cached = this.socket.read(content_length)\n this.socket.close()\n this.socket = null\n }\n\n // print(\"Buffer length:\", len(self._cached))\n return this._cached\n }\n\n /** \n * The HTTP content, encoded into a string according to the HTTP header encoding\n */\n get text() {\n const b = this.content;\n return b ? b.toString() : undefined;\n }\n\n get json() {\n return JSON.parse(this.text)\n }\n\n public toString() {\n return `HTTP ${this.status_code}; ${Object.keys(this.headers).length} headers; ${this._cached ? this._cached.length : -1} bytes content`\n }\n }\n\n export interface RequestOptions {\n data?: string | Buffer;\n json?: any; // will call JSON.stringify()\n headers?: StringMap;\n stream?: boolean;\n timeout?: number; // in ms\n }\n\n export function dataAsBuffer(data: string | Buffer): Buffer {\n if (data == null)\n return null\n if (typeof data == \"string\")\n return control.createBufferFromUTF8(data)\n return data\n }\n\n /*\n >>> \"a,b,c,d,e\".split(\",\", 2)\n ['a', 'b', 'c,d,e']\n */\n function pysplit(str: string, sep: string, limit: number) {\n const arr = str.split(sep)\n if (arr.length >= limit) {\n return arr.slice(0, limit).concat([arr.slice(limit).join(sep)])\n } else {\n return arr\n }\n }\n\n\n /** Perform an HTTP request to the given url which we will parse to determine\nwhether to use SSL ('https://') or not. We can also send some provided 'data'\nor a json dictionary which we will stringify. 'headers' is optional HTTP headers\nsent along. 'stream' will determine if we buffer everything, or whether to only\nread only when requested\n \n*/\n export function request(method: string, url: string, options?: RequestOptions): net.Response {\n net.log(`${method} ${url}`);\n\n if (!net.instance().controller) {\n // no controller\n const r = new net.Response(null);\n r.status_code = 418; // teapot\n r.reason = \"net controller not configured\";\n return r;\n }\n\n try {\n return internalRequest(method, url, options);\n } catch (e) {\n const r = new net.Response(null);\n r.status_code = 418; // teapot\n r.reason = \"\" + e;\n return r;\n }\n }\n\n function internalRequest(method: string, url: string, options?: RequestOptions): net.Response {\n if (!options) options = {};\n if (!options.headers) {\n options.headers = {}\n }\n\n const tmp = pysplit(url, \"/\", 3)\n let proto = tmp[0]\n let host = tmp[2]\n let path = tmp[3] || \"\"\n // replace spaces in path\n // TODO\n // path = path.replace(\" \", \"%20\")\n\n let port = 0\n if (proto == \"http:\") {\n port = 80\n } else if (proto == \"https:\") {\n port = 443\n } else {\n control.fail(\"Unsupported protocol: \" + proto)\n }\n\n if (host.indexOf(\":\") >= 0) {\n const tmp = host.split(\":\")\n host = tmp[0]\n port = parseInt(tmp[1])\n }\n\n let sock: Socket;\n if (proto == \"https:\") {\n // for SSL we need to know the host name\n sock = net.instance().createSocket(host, port, true)\n } else {\n sock = net.instance().createSocket(host, port, false)\n }\n // our response\n let resp = new Response(sock)\n // socket read timeout\n sock.setTimeout(options.timeout)\n\n sock.connect();\n sock.send(`${method} /${path} HTTP/1.0\\r\\n`)\n\n if (!options.headers[\"Host\"])\n sock.send(`Host: ${host}\\r\\n`)\n\n if (!options.headers[\"User-Agent\"])\n sock.send(\"User-Agent: MakeCode ESP32\\r\\n\")\n\n // Iterate over keys to avoid tuple alloc\n for (let k of Object.keys(options.headers))\n sock.send(`${k}: ${options.headers[k]}\\r\\n`)\n\n if (options.json != null) {\n control.assert(options.data == null, 100)\n options.data = JSON.stringify(options.json)\n sock.send(\"Content-Type: application/json\\r\\n\")\n }\n\n let dataBuf = dataAsBuffer(options.data)\n\n if (dataBuf)\n sock.send(`Content-Length: ${dataBuf.length}\\r\\n`)\n\n sock.send(\"\\r\\n\")\n if (dataBuf)\n sock.send(dataBuf)\n\n let line = sock.readLine()\n // print(line)\n let line2 = pysplit(line, \" \", 2)\n let status = parseInt(line2[1])\n let reason = \"\"\n if (line2.length > 2) {\n reason = line2[2]\n }\n\n while (true) {\n line = sock.readLine()\n if (!line || line == \"\\r\\n\") {\n break\n }\n\n // print(\"**line: \", line)\n const tmp = pysplit(line, \": \", 1)\n let title = tmp[0]\n let content = tmp[1]\n if (title && content) {\n resp.headers[title.toLowerCase()] = content.toLowerCase()\n }\n }\n\n /*\n \n elif line.startswith(b\"Location:\") and not 200 <= status <= 299:\n raise NotImplementedError(\"Redirects not yet supported\")\n */\n\n if ((resp.headers[\"transfer-encoding\"] || \"\").indexOf(\"chunked\") >= 0)\n control.fail(\"not supported chunked encoding\")\n\n resp.status_code = status\n resp.reason = reason\n return resp\n }\n\n /** \n * Send HTTP HEAD request \n **/\n export function head(url: string, options?: RequestOptions) {\n return request(\"HEAD\", url, options)\n }\n\n /** \n * Send HTTP GET request \n **/\n export function get(url: string, options?: RequestOptions) {\n return request(\"GET\", url, options)\n }\n\n /** \n * Send HTTP GET request and return text \n **/\n //% blockId=netgetstring block=\"get string $url\"\n export function getString(url: string, options?: RequestOptions): string {\n const res = get(url, options)\n const rv = res.status_code == 200 ? res.text : undefined\n res.close()\n return rv\n }\n\n /** \n * Send HTTP GET request and return JSON \n **/\n //% blockId=netgetjson block=\"get json $url\"\n export function getJSON(url: string, options?: RequestOptions): any {\n options = options || {};\n options.headers = options.headers || {};\n options.headers[\"accept\"] = options.headers[\"accept\"] || \"application/json\";\n const res = get(url, options);\n const rv = res.status_code == 200 ? res.json : undefined;\n res.close()\n return rv\n }\n\n /** Send HTTP POST request */\n export function post(url: string, options?: RequestOptions) {\n return request(\"POST\", url, options)\n }\n\n /** Send HTTP PATCH request */\n export function patch(url: string, options?: RequestOptions) {\n return request(\"PATCH\", url, options)\n }\n\n /** Send HTTP PUT request */\n export function put(url: string, options?: RequestOptions) {\n return request(\"PUT\", url, options)\n }\n\n /** Send HTTP DELETE request */\n export function del(url: string, options?: RequestOptions) {\n return request(\"DELETE\", url, options)\n }\n}"
2025
2025
  },
2026
2026
  "net-game": {
2027
- "pxt.json": "{\n \"name\": \"net-game\",\n \"description\": \"WiFi support in Arcade - beta\",\n \"dependencies\": {\n \"core\": \"*\",\n \"settings\": \"*\",\n \"net\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"settings.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2027
+ "pxt.json": "{\n \"name\": \"net-game\",\n \"description\": \"WiFi support in Arcade - beta\",\n \"dependencies\": {\n \"core\": \"*\",\n \"settings\": \"*\",\n \"net\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"settings.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2028
2028
  "settings.ts": "namespace net {\n class Configurator {\n private accessPoints: net.AccessPoint[];\n private apIndex: number;\n private scanning: boolean;\n private wifi: net.Controller;\n\n constructor() {\n this.scanning = false;\n this.apIndex = 0;\n }\n\n private select() {\n const ap = this.accessPoints && this.accessPoints[this.apIndex];\n if (ap) {\n const wifis = net.knownAccessPoints();\n const known = wifis[ap.ssid] !== undefined ? \"*\" : \"?\";\n console.log(`${known} ${ap.ssid}`);\n }\n }\n\n private connect() {\n console.log(\"connecting...\")\n this.wifi.connect();\n console.log(this.wifi.isConnected ? `connected to ${this.wifi.ssid}` : `disconnected`);\n if (this.wifi.isConnected) {\n for (let i = 0; i < 3; ++i) {\n const ping = this.wifi.ping(\"bing.com\")\n console.log(`bing.com ping ${ping}ms`);\n }\n }\n }\n\n private scan() {\n if (this.scanning) return;\n\n this.scanning = true;\n const mac = this.wifi.MACaddress;\n console.log(`MAC: ${mac ? mac.toHex() : \"???\"}`)\n console.log(\"scanning...\")\n control.runInBackground(() => {\n this.accessPoints = this.wifi.scanNetworks()\n if (this.accessPoints && this.accessPoints.length) {\n const wifis = net.knownAccessPoints();\n for (let i = 0; i < this.accessPoints.length; ++i) {\n const ap = this.accessPoints[i];\n const known = wifis[ap.ssid] !== undefined ? \"*\" : \"?\";\n console.log(` ${known} ${ap.ssid}`);\n }\n console.log(\" \");\n this.apIndex = 0;\n console.log(\"*: AP known\")\n console.log(\"up/down: select AP\")\n console.log(\"left: erase AP info\")\n console.log(\"right: enter AP password\")\n console.log(\"A: connect\")\n console.log(\" \");\n this.select();\n }\n this.scanning = false;\n });\n }\n\n main() {\n this.wifi = net.instance().controller;\n if (!this.wifi) {\n console.log(\"WiFi module not configured\");\n return;\n }\n pauseUntil(() => this.wifi.isIdle, 30000);\n if (!this.wifi.isIdle) {\n console.log(\"WiFi module not responding\")\n return;\n }\n controller.up.onEvent(ControllerButtonEvent.Pressed, () => {\n this.apIndex = this.apIndex + 1;\n if (this.accessPoints)\n this.apIndex = this.apIndex % this.accessPoints.length;\n this.select();\n })\n controller.down.onEvent(ControllerButtonEvent.Pressed, () => {\n this.apIndex = this.apIndex - 1;\n this.apIndex = (this.apIndex + this.accessPoints.length) % this.accessPoints.length;\n this.select();\n })\n controller.left.onEvent(ControllerButtonEvent.Pressed, () => {\n const ap = this.accessPoints && this.accessPoints[this.apIndex];\n if (!ap) return;\n net.updateAccessPoint(ap.ssid, undefined);\n console.log(`password erased`)\n this.scan();\n })\n controller.right.onEvent(ControllerButtonEvent.Pressed, () => {\n const ap = this.accessPoints && this.accessPoints[this.apIndex];\n if (!ap) return;\n game.consoleOverlay.setVisible(false);\n const pwd = game.askForString(`password for ${ap.ssid}`, 24);\n game.consoleOverlay.setVisible(true);\n net.updateAccessPoint(ap.ssid, pwd);\n console.log(`password saved`)\n this.scan();\n })\n controller.A.onEvent(ControllerButtonEvent.Pressed, () => {\n this.connect();\n })\n controller.B.onEvent(ControllerButtonEvent.Pressed, () => {\n game.popScene();\n game.consoleOverlay.setVisible(false);\n });\n this.scan();\n }\n }\n\n function wifiSystemMenu() {\n scene.systemMenu.closeMenu();\n game.pushScene();\n game.consoleOverlay.setVisible(true);\n console.log(\"WiFi configuration\")\n const config = new Configurator();\n config.main()\n }\n\n scene.systemMenu.addEntry(\n () => \"WiFi\",\n () => wifiSystemMenu(),\n img`\n . . . . . . . . . . . . . . . .\n . . . . . . 8 8 8 8 . . . . . .\n . . . . 8 8 8 6 6 6 8 8 . . . .\n . . . 8 6 6 6 6 6 6 6 6 8 . . .\n . . 8 6 6 . . . . . . 6 6 8 . .\n . 8 6 6 . . . . . . . . 6 6 8 .\n 8 6 6 . . . 8 8 8 8 . . . 6 6 8\n . 6 . . . 8 6 6 6 6 8 . . . 6 .\n . . . . 8 6 6 6 6 6 6 8 . . . .\n . . . 8 6 6 . . . . 6 6 8 . . .\n . . . . 6 . . . . . . 6 . . . .\n . . . . . . . 8 8 . . . . . . .\n . . . . . . 8 6 6 8 . . . . . .\n . . . . . . 6 6 6 6 . . . . . .\n . . . . . . . 6 6 . . . . . . .\n . . . . . . . . . . . . . . . .\n`);\n}"
2029
2029
  },
2030
2030
  "palette": {
2031
2031
  "README.md": "# Palette\n\nHelpers to manipulate palette in games.",
2032
2032
  "palette.ts": "/**\n * Update the current scene palette\n */\nnamespace palette {\n /**\n * The default palette buffer for the project\n */\n //% whenUsed\n const defaultPaletteBuffer = hex`__palette`\n\n /**\n * Returns a clone of the default palette\n */\n export function defaultPalette(): color.ColorBuffer {\n return color.ColorBuffer.fromBuffer(defaultPaletteBuffer.slice(), color.ColorBufferLayout.RGB);\n }\n\n const FIELD = \"__palette\";\n /**\n * Dynamically set all or part of the game's current palette\n *\n * @param palette The colors to set\n * @param pOffset The offset to start copying from the palette\n */\n export function setColors(palette: color.ColorBuffer, pOffset = 0) {\n const userPalette = getCurrentColors();\n userPalette.write(pOffset, palette);\n image.setPalette(userPalette.buf);\n\n // make sure to clean up\n game.addScenePushHandler(scenePush);\n game.addScenePopHandler(scenePop);\n }\n\n /**\n * Get the palette that is currently being used\n */\n export function getCurrentColors() {\n const scene = game.currentScene();\n let userPalette = scene.data[FIELD] as color.ColorBuffer;\n if (!userPalette)\n userPalette = scene.data[FIELD] = defaultPalette();\n return userPalette;\n }\n\n function scenePush(scene: scene.Scene) {\n if (scene.data[FIELD]) {\n const userPalette = scene.data[FIELD] as color.ColorBuffer;\n image.setPalette(userPalette.buf);\n }\n }\n\n function scenePop(scene: scene.Scene) {\n if (scene.data[FIELD]) {\n scene.data[FIELD] = undefined;\n image.setPalette(defaultPaletteBuffer);\n }\n }\n\n /**\n * Reset to default palette\n */\n export function reset() {\n const scene = game.currentScene();\n scene.data[FIELD] = undefined;\n image.setPalette(defaultPaletteBuffer);\n }\n}\n",
2033
- "pxt.json": "{\n \"name\": \"palette\",\n \"description\": \"Palette manipulations\",\n \"dependencies\": {\n \"color\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"palette.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"weight\": 75,\n \"icon\": \"/static/libs/palette.png\"\n}\n",
2033
+ "pxt.json": "{\n \"name\": \"palette\",\n \"description\": \"Palette manipulations\",\n \"dependencies\": {\n \"color\": \"*\",\n \"game\": \"*\"\n },\n \"files\": [\n \"palette.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"weight\": 75,\n \"icon\": \"/static/libs/palette.png\"\n}\n",
2034
2034
  "test.ts": "\nlet mySprite = sprites.create(img`\n0 1 2 3\n4 5 6 7\n8 9 a b\nc d e f\n`.doubled().doubled().doubled().doubled(), SpriteKind.Player)\n\ncontroller.A.onEvent(ControllerButtonEvent.Pressed, function () {\n const p = palette.defaultPalette();\n for (let i = 0; i < p.length; ++i) {\n p.setColor(i, color.rgb(i * 16, 0, 255 - i * 16));\n }\n p.setColor(0, 0)\n palette.setColors(p)\n})\n\ncontroller.B.onEvent(ControllerButtonEvent.Pressed, function () {\n palette.reset()\n})\n\n"
2035
2035
  },
2036
2036
  "power": {
2037
2037
  "power.ts": "/**\n * Power and sleep management\n */\n//% advanced=true icon=\"\\uf011\" color=\"#898989\"\n//% weight=1 blockGap=8\nnamespace power {\n let _poked: number;\n let _timeout: number;\n\n /**\n * Set the no-activity duration after which the device should go to deep sleep.\n * @param seconds duration in seconds until the device should be put in lower power mode\n */\n //% blockId=powersetdeepsleeptimout block=\"power set deep sleep timeout to %seconds s\"\n //% seconds.defl=60\n //% help=/power/set-deep-sleep-timeout\n export function setDeepSleepTimeout(seconds: number) {\n init();\n _timeout = seconds * 1000;\n }\n\n /**\n * Poke the activity watcher to keep the device awake.\n */\n //% blockId=powerpke block=\"power poke\"\n //% help=/power/poke\n export function poke() {\n init();\n _poked = control.millis();\n }\n\n /**\n * Check if the device has had any \"pokes\" and needs to go into deep sleep mode.\n */\n //% blockId=powercheckdeepsleep block=\"power check deep sleep\"\n //% help=/power/check-deep-sleep\n export function checkDeepSleep() {\n init();\n const p = _poked || 0;\n const to = _timeout || 0;\n if (to > 0 && \n control.millis() - p > to &&\n !control.isUSBInitialized()) {\n // going to deep sleep\n deepSleep();\n }\n }\n\n /**\n * Put the device into a deep sleep state.\n */\n //% blockId=powerdeepsleep block=\"power deep sleep\"\n //% shim=pxt::deepSleep\n //% help=/power/deep-sleep\n export function deepSleep() {\n }\n\n function init() {\n if (_timeout !== undefined) return;\n\n // read default value\n _timeout = control.getConfigValue(DAL.CFG_POWER_DEEPSLEEP_TIMEOUT, -1) * 1000;\n // ensure deepsleep is long enough\n const minDeepSleepTimeout = 300000;\n if (_timeout > 0 && _timeout < minDeepSleepTimeout)\n _timeout = minDeepSleepTimeout;\n }\n}\n",
2038
- "pxt.json": "{\n \"name\": \"power\",\n \"description\": \"Power and sleep management\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"power.ts\"\n ],\n \"testFiles\": [],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n"
2038
+ "pxt.json": "{\n \"name\": \"power\",\n \"description\": \"Power and sleep management\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"power.ts\"\n ],\n \"testFiles\": [],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n"
2039
2039
  },
2040
2040
  "radio": {
2041
2041
  "README.md": "# radio\n\nThe radio library.\n\n",
2042
2042
  "enums.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace radio {\n}\n\n// Auto-generated. Do not edit. Really.\n",
2043
- "pxt.json": "{\n \"name\": \"radio\",\n \"description\": \"The radio services\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"radio.cpp\",\n \"radio.ts\",\n \"targetoverrides.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"icon\": \"/static/libs/radio.png\"\n}\n",
2043
+ "pxt.json": "{\n \"name\": \"radio\",\n \"description\": \"The radio services\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"radio.cpp\",\n \"radio.ts\",\n \"targetoverrides.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"icon\": \"/static/libs/radio.png\"\n}\n",
2044
2044
  "radio.cpp": "#include \"pxt.h\"\n\n// micro:bit dal\n#if defined(MICROBIT_H) \n\n#define CODAL_RADIO MicroBitRadio\n#define DEVICE_OK MICROBIT_OK\n#define DEVICE_NOT_SUPPORTED MICROBIT_NOT_SUPPORTED\n#define CODAL_EVENT MicroBitEvent\n#define CODAL_RADIO_MICROBIT_DAL 1\n\n// any other NRF52 board\n#elif defined(NRF52_SERIES)\n\n#include \"NRF52Radio.h\"\n#define CODAL_RADIO codal::NRF52Radio\n#define CODAL_EVENT codal::Event\n\n#endif\n\nusing namespace pxt;\n\n#ifndef MICROBIT_RADIO_MAX_PACKET_SIZE\n#define MICROBIT_RADIO_MAX_PACKET_SIZE 32\n#endif\n\n#ifndef DEVICE_RADIO_MAX_PACKET_SIZE\n#define DEVICE_RADIO_MAX_PACKET_SIZE MICROBIT_RADIO_MAX_PACKET_SIZE\n#endif\n\n#ifndef MICROBIT_ID_RADIO\n#define MICROBIT_ID_RADIO 29\n#endif\n\n#ifndef DEVICE_ID_RADIO\n#define DEVICE_ID_RADIO MICROBIT_ID_RADIO\n#endif\n\n#ifndef MICROBIT_RADIO_EVT_DATAGRAM\n#define MICROBIT_RADIO_EVT_DATAGRAM 1 // Event to signal that a new datagram has been received.\n#endif\n\n#ifndef DEVICE_RADIO_EVT_DATAGRAM\n#define DEVICE_RADIO_EVT_DATAGRAM MICROBIT_RADIO_EVT_DATAGRAM\n#endif\n\n//% color=#E3008C weight=96 icon=\"\\uf012\"\nnamespace radio {\n \n#if CODAL_RADIO_MICROBIT_DAL\n CODAL_RADIO* getRadio() {\n return &uBit.radio;\n }\n#elif defined(CODAL_RADIO)\nclass RadioWrap {\n CODAL_RADIO radio;\n public:\n RadioWrap() \n : radio()\n {}\n\n CODAL_RADIO* getRadio() {\n return &radio;\n }\n};\nSINGLETON(RadioWrap);\nCODAL_RADIO* getRadio() {\n auto wrap = getRadioWrap();\n if (NULL != wrap)\n return wrap->getRadio(); \n return NULL;\n}\n#endif // #else\n\n bool radioEnabled = false;\n bool init = false;\n int radioEnable() {\n#ifdef CODAL_RADIO\n auto radio = getRadio();\n if (NULL == radio) \n return DEVICE_NOT_SUPPORTED;\n\n if (init && !radioEnabled) {\n //If radio was explicitly disabled from a call to off API\n //We don't want to enable it here. User needs to call on API first.\n return DEVICE_NOT_SUPPORTED;\n }\n\n int r = radio->enable();\n if (r != DEVICE_OK) {\n target_panic(43);\n return r;\n }\n if (!init) {\n getRadio()->setGroup(0); //Default group zero. This used to be pxt::programHash()\n getRadio()->setTransmitPower(6); // start with high power by default\n init = true;\n }\n radioEnabled = true;\n return r;\n#else\n return DEVICE_NOT_SUPPORTED;\n#endif\n }\n\n /**\n * Disables the radio for use as a multipoint sender/receiver.\n * Disabling radio will help conserve battery power when it is not in use.\n */\n //% help=radio/off\n void off() {\n#ifdef CODAL_RADIO\n auto radio = getRadio();\n if (NULL == radio)\n return;\n\n int r = radio->disable();\n if (r != DEVICE_OK) {\n target_panic(43);\n } else {\n radioEnabled = false;\n }\n#else\n return;\n#endif\n }\n\n /**\n * Initialises the radio for use as a multipoint sender/receiver\n * Only useful when the radio.off() is used beforehand.\n */\n //% help=radio/on\n void on() {\n#ifdef CODAL_RADIO\n auto radio = getRadio();\n if (NULL == radio)\n return;\n\n int r = radio->enable();\n if (r != DEVICE_OK) {\n target_panic(43);\n } else {\n radioEnabled = true;\n }\n#else\n return;\n#endif\n }\n\n /**\n * Sends an event over radio to neigboring devices\n */\n //% blockId=radioRaiseEvent block=\"radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id\"\n //% blockExternalInputs=1\n //% advanced=true\n //% weight=1\n //% help=radio/raise-event\n void raiseEvent(int src, int value) {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK) return;\n\n getRadio()->event.eventReceived(CODAL_EVENT(src, value, CREATE_ONLY));\n#endif \n }\n\n /**\n * Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer.\n * @returns NULL if no packet available\n */\n //%\n Buffer readRawPacket() {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK) return NULL;\n\n auto p = getRadio()->datagram.recv();\n#if CODAL_RADIO_MICROBIT_DAL\n if (p == PacketBuffer::EmptyPacket)\n return NULL;\n int rssi = p.getRSSI();\n auto length = p.length();\n auto bytes = p.getBytes();\n#else\n // TODO: RSSI support\n int rssi = -73; \n auto length = p.length();\n auto bytes = p.getBytes();\n if (length == 0)\n return NULL;\n#endif\n\n uint8_t buf[DEVICE_RADIO_MAX_PACKET_SIZE + sizeof(int)]; // packet length + rssi\n memset(buf, 0, sizeof(buf));\n memcpy(buf, bytes, length); // data\n memcpy(buf + DEVICE_RADIO_MAX_PACKET_SIZE, &rssi, sizeof(int)); // RSSi - assumes Int32LE layout\n return mkBuffer(buf, sizeof(buf));\n#else\n return NULL;\n#endif \n }\n\n /**\n * Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet)\n */\n //% async\n void sendRawPacket(Buffer msg) {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK || NULL == msg) return;\n\n // don't send RSSI data; and make sure no buffer underflow\n int len = msg->length - sizeof(int);\n if (len > 0)\n getRadio()->datagram.send(msg->data, len);\n#endif \n }\n\n /**\n * Used internally by the library.\n */\n //% help=radio/on-data-received\n //% weight=0\n //% blockId=radio_datagram_received_event block=\"radio on data received\" blockGap=8\n //% deprecated=true blockHidden=1\n void onDataReceived(Action body) {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK) return;\n\n registerWithDal(DEVICE_ID_RADIO, DEVICE_RADIO_EVT_DATAGRAM, body);\n getRadio()->datagram.recv(); // wake up read code\n#endif \n }\n\n /**\n * Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.\n * @param id the group id between ``0`` and ``255``, eg: 1\n */\n //% help=radio/set-group\n //% weight=100\n //% blockId=radio_set_group block=\"radio set group %ID\"\n //% id.min=0 id.max=255\n //% group=\"Group\"\n void setGroup(int id) {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK) return;\n\n getRadio()->setGroup(id);\n#endif \n }\n\n /**\n * Change the output power level of the transmitter to the given value.\n * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. eg: 7\n */\n //% help=radio/set-transmit-power\n //% weight=9 blockGap=8\n //% blockId=radio_set_transmit_power block=\"radio set transmit power %power\"\n //% power.min=0 power.max=7\n //% advanced=true\n void setTransmitPower(int power) {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK) return;\n\n getRadio()->setTransmitPower(power);\n#endif \n }\n\n /**\n * Change the transmission and reception band of the radio to the given channel\n * @param band a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz.\n **/\n //% help=radio/set-frequency-band\n //% weight=8 blockGap=8\n //% blockId=radio_set_frequency_band block=\"radio set frequency band %band\"\n //% band.min=0 band.max=83\n //% advanced=true\n void setFrequencyBand(int band) {\n#ifdef CODAL_RADIO \n if (radioEnable() != DEVICE_OK) return;\n getRadio()->setFrequencyBand(band);\n#endif \n }\n}\n",
2045
2045
  "radio.ts": "\nenum RadioPacketProperty {\n //% blockIdentity=radio._packetProperty\n //% block=\"signal strength\"\n SignalStrength = 2,\n //% blockIdentity=radio._packetProperty\n //% block=\"time\"\n Time = 0,\n //% block=\"serial number\"\n //% blockIdentity=radio._packetProperty\n SerialNumber = 1\n}\n\n/**\n * Communicate data using radio packets\n */\n//% color=#E3008C weight=96 icon=\"\\uf012\" groups='[\"Group\", \"Broadcast\", \"Send\", \"Receive\"]'\nnamespace radio {\n\n // keep in sync with CODAL\n const RADIO_MAX_PACKET_SIZE = 32;\n const MAX_FIELD_DOUBLE_NAME_LENGTH = 8;\n const MAX_PAYLOAD_LENGTH = 20;\n const PACKET_PREFIX_LENGTH = 9;\n const VALUE_PACKET_NAME_LEN_OFFSET = 13;\n const DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET = 17;\n\n // Packet Spec:\n // | 0 | 1 ... 4 | 5 ... 8 | 9 ... 28\n // ----------------------------------------------------------------\n // | packet type | system time | serial number | payload\n //\n // Serial number defaults to 0 unless enabled by user\n\n // payload: number (9 ... 12)\n export const PACKET_TYPE_NUMBER = 0;\n // payload: number (9 ... 12), name length (13), name (14 ... 26)\n export const PACKET_TYPE_VALUE = 1;\n // payload: string length (9), string (10 ... 28)\n export const PACKET_TYPE_STRING = 2;\n // payload: buffer length (9), buffer (10 ... 28)\n export const PACKET_TYPE_BUFFER = 3;\n // payload: number (9 ... 16)\n export const PACKET_TYPE_DOUBLE = 4;\n // payload: number (9 ... 16), name length (17), name (18 ... 26)\n export const PACKET_TYPE_DOUBLE_VALUE = 5;\n\n let transmittingSerial: boolean;\n let initialized = false;\n\n export let lastPacket: RadioPacket;\n let onReceivedNumberHandler: (receivedNumber: number) => void;\n let onReceivedValueHandler: (name: string, value: number) => void;\n let onReceivedStringHandler: (receivedString: string) => void;\n let onReceivedBufferHandler: (receivedBuffer: Buffer) => void;\n\n function init() {\n if (initialized) return;\n initialized = true;\n onDataReceived(handleDataReceived);\n }\n\n function handleDataReceived() {\n let buffer: Buffer = readRawPacket();\n while (buffer) {\n lastPacket = RadioPacket.getPacket(buffer);\n switch (lastPacket.packetType) {\n case PACKET_TYPE_NUMBER:\n case PACKET_TYPE_DOUBLE:\n if (onReceivedNumberHandler)\n onReceivedNumberHandler(lastPacket.numberPayload);\n break;\n case PACKET_TYPE_VALUE:\n case PACKET_TYPE_DOUBLE_VALUE:\n if (onReceivedValueHandler)\n onReceivedValueHandler(lastPacket.stringPayload, lastPacket.numberPayload);\n break;\n case PACKET_TYPE_BUFFER:\n if (onReceivedBufferHandler)\n onReceivedBufferHandler(lastPacket.bufferPayload);\n break;\n case PACKET_TYPE_STRING:\n if (onReceivedStringHandler)\n onReceivedStringHandler(lastPacket.stringPayload);\n break;\n }\n // read next packet if any\n buffer = readRawPacket();\n }\n }\n\n /**\n * Registers code to run when the radio receives a number.\n */\n //% help=radio/on-received-number\n //% blockId=radio_on_number_drag block=\"on radio received\" blockGap=16\n //% useLoc=\"radio.onDataPacketReceived\" draggableParameters=reporter\n //% group=\"Receive\"\n //% weight=20\n export function onReceivedNumber(cb: (receivedNumber: number) => void) {\n init();\n onReceivedNumberHandler = cb;\n }\n\n /**\n * Registers code to run when the radio receives a key value pair.\n */\n //% help=radio/on-received-value\n //% blockId=radio_on_value_drag block=\"on radio received\" blockGap=16\n //% useLoc=\"radio.onDataPacketReceived\" draggableParameters=reporter\n //% group=\"Receive\"\n //% weight=19\n export function onReceivedValue(cb: (name: string, value: number) => void) {\n init();\n onReceivedValueHandler = cb;\n }\n\n /**\n * Registers code to run when the radio receives a string.\n */\n //% help=radio/on-received-string\n //% blockId=radio_on_string_drag block=\"on radio received\" blockGap=16\n //% useLoc=\"radio.onDataPacketReceived\" draggableParameters=reporter\n //% group=\"Receive\"\n //% weight=18\n export function onReceivedString(cb: (receivedString: string) => void) {\n init();\n onReceivedStringHandler = cb;\n }\n\n /**\n * Registers code to run when the radio receives a buffer.\n */\n //% help=radio/on-received-buffer blockHidden=1\n //% blockId=radio_on_buffer_drag block=\"on radio received\" blockGap=16\n //% useLoc=\"radio.onDataPacketReceived\" draggableParameters=reporter\n export function onReceivedBuffer(cb: (receivedBuffer: Buffer) => void) {\n init();\n onReceivedBufferHandler = cb;\n }\n\n /**\n * Returns properties of the last radio packet received.\n * @param type the type of property to retrieve from the last packet\n */\n //% help=radio/received-packet\n //% blockGap=8\n //% blockId=radio_received_packet block=\"received packet %type=radio_packet_property\" blockGap=16\n //% group=\"Receive\"\n //% weight=16\n export function receivedPacket(type: number) {\n if (lastPacket) {\n switch (type) {\n case RadioPacketProperty.Time: return lastPacket.time;\n case RadioPacketProperty.SerialNumber: return lastPacket.serial;\n case RadioPacketProperty.SignalStrength: return lastPacket.signal;\n }\n }\n return 0;\n }\n\n /**\n * Gets a packet property.\n * @param type the packet property type, eg: PacketProperty.time\n */\n //% blockId=radio_packet_property block=\"%note\"\n //% shim=TD_ID blockHidden=1\n export function _packetProperty(type: RadioPacketProperty): number {\n return type;\n }\n\n export class RadioPacket {\n public static getPacket(data: Buffer) {\n if (!data) return undefined;\n // last 4 bytes is RSSi\n return new RadioPacket(data);\n }\n\n public static mkPacket(packetType: number) {\n const res = new RadioPacket();\n res.data[0] = packetType;\n return res;\n }\n\n private constructor(public readonly data?: Buffer) {\n if (!data) this.data = control.createBuffer(RADIO_MAX_PACKET_SIZE + 4);\n }\n\n get signal() {\n return this.data.getNumber(NumberFormat.Int32LE, this.data.length - 4);\n }\n\n get packetType() {\n return this.data[0];\n }\n\n get time() {\n return this.data.getNumber(NumberFormat.Int32LE, 1);\n }\n\n set time(val: number) {\n this.data.setNumber(NumberFormat.Int32LE, 1, val);\n }\n\n get serial() {\n return this.data.getNumber(NumberFormat.Int32LE, 5);\n }\n\n set serial(val: number) {\n this.data.setNumber(NumberFormat.Int32LE, 5, val);\n }\n\n get stringPayload() {\n const offset = getStringOffset(this.packetType) as number;\n return offset ? this.data.slice(offset + 1, this.data[offset]).toString() : undefined;\n }\n\n set stringPayload(val: string) {\n const offset = getStringOffset(this.packetType) as number;\n if (offset) {\n const buf = control.createBufferFromUTF8(truncateString(val, getMaxStringLength(this.packetType)));\n this.data[offset] = buf.length;\n this.data.write(offset + 1, buf);\n }\n }\n\n get numberPayload() {\n switch (this.packetType) {\n case PACKET_TYPE_NUMBER:\n case PACKET_TYPE_VALUE:\n return this.data.getNumber(NumberFormat.Int32LE, PACKET_PREFIX_LENGTH);\n case PACKET_TYPE_DOUBLE:\n case PACKET_TYPE_DOUBLE_VALUE:\n return this.data.getNumber(NumberFormat.Float64LE, PACKET_PREFIX_LENGTH);\n }\n return undefined;\n }\n\n set numberPayload(val: number) {\n switch (this.packetType) {\n case PACKET_TYPE_NUMBER:\n case PACKET_TYPE_VALUE:\n this.data.setNumber(NumberFormat.Int32LE, PACKET_PREFIX_LENGTH, val);\n break;\n case PACKET_TYPE_DOUBLE:\n case PACKET_TYPE_DOUBLE_VALUE:\n this.data.setNumber(NumberFormat.Float64LE, PACKET_PREFIX_LENGTH, val);\n break;\n }\n }\n\n get bufferPayload() {\n const len = this.data[PACKET_PREFIX_LENGTH];\n return this.data.slice(PACKET_PREFIX_LENGTH + 1, len);\n }\n\n set bufferPayload(b: Buffer) {\n const len = Math.min(b.length, MAX_PAYLOAD_LENGTH - 1);\n this.data[PACKET_PREFIX_LENGTH] = len;\n this.data.write(PACKET_PREFIX_LENGTH + 1, b.slice(0, len));\n }\n\n hasString() {\n return this.packetType === PACKET_TYPE_STRING ||\n this.packetType === PACKET_TYPE_VALUE ||\n this.packetType === PACKET_TYPE_DOUBLE_VALUE;\n }\n\n hasNumber() {\n return this.packetType === PACKET_TYPE_NUMBER ||\n this.packetType === PACKET_TYPE_DOUBLE ||\n this.packetType === PACKET_TYPE_VALUE ||\n this.packetType === PACKET_TYPE_DOUBLE_VALUE;\n }\n }\n\n /**\n * Broadcasts a number over radio to any connected micro:bit in the group.\n */\n //% help=radio/send-number\n //% weight=60\n //% blockId=radio_datagram_send block=\"radio send number %value\" blockGap=8\n //% group=\"Send\"\n export function sendNumber(value: number) {\n let packet: RadioPacket;\n\n if (value === (value | 0)) {\n packet = RadioPacket.mkPacket(PACKET_TYPE_NUMBER);\n }\n else {\n packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE);\n }\n\n packet.numberPayload = value;\n sendPacket(packet);\n }\n\n /**\n * Broadcasts a name / value pair along with the device serial number\n * and running time to any connected micro:bit in the group. The name can\n * include no more than 8 characters.\n * @param name the field name (max 8 characters), eg: \"name\"\n * @param value the numeric value\n */\n //% help=radio/send-value\n //% weight=59\n //% blockId=radio_datagram_send_value block=\"radio send|value %name|= %value\" blockGap=8\n //% group=\"Send\"\n export function sendValue(name: string, value: number) {\n let packet: RadioPacket;\n\n if (value === (value | 0)) {\n packet = RadioPacket.mkPacket(PACKET_TYPE_VALUE);\n }\n else {\n packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE_VALUE);\n }\n\n packet.numberPayload = value;\n packet.stringPayload = name;\n sendPacket(packet);\n }\n\n /**\n * Broadcasts a string along with the device serial number\n * and running time to any connected micro:bit in the group.\n */\n //% help=radio/send-string\n //% weight=58\n //% blockId=radio_datagram_send_string block=\"radio send string %msg\"\n //% msg.shadowOptions.toString=true\n //% group=\"Send\"\n export function sendString(value: string) {\n const packet = RadioPacket.mkPacket(PACKET_TYPE_STRING);\n packet.stringPayload = value;\n sendPacket(packet);\n }\n\n /**\n * Broadcasts a buffer (up to 19 bytes long) along with the device serial number\n * and running time to any connected micro:bit in the group.\n */\n //% help=radio/send-buffer\n //% weight=57\n //% advanced=true\n export function sendBuffer(msg: Buffer) {\n const packet = RadioPacket.mkPacket(PACKET_TYPE_BUFFER);\n packet.bufferPayload = msg;\n sendPacket(packet);\n }\n\n /**\n * Set the radio to transmit the serial number in each message.\n * @param transmit value indicating if the serial number is transmitted, eg: true\n */\n //% help=radio/set-transmit-serial-number\n //% weight=8 blockGap=8\n //% blockId=radio_set_transmit_serial_number block=\"radio set transmit serial number %transmit\"\n //% advanced=true\n export function setTransmitSerialNumber(transmit: boolean) {\n transmittingSerial = transmit;\n }\n\n function sendPacket(packet: RadioPacket) {\n packet.time = control.millis();\n packet.serial = transmittingSerial ? control.deviceSerialNumber() : 0;\n radio.sendRawPacket(packet.data);\n }\n\n function truncateString(str: string, bytes: number) {\n str = str.substr(0, bytes);\n let buff = control.createBufferFromUTF8(str);\n\n while (buff.length > bytes) {\n str = str.substr(0, str.length - 1);\n buff = control.createBufferFromUTF8(str);\n }\n\n return str;\n }\n\n function getStringOffset(packetType: number) {\n switch (packetType) {\n case PACKET_TYPE_STRING:\n return PACKET_PREFIX_LENGTH;\n case PACKET_TYPE_VALUE:\n return VALUE_PACKET_NAME_LEN_OFFSET;\n case PACKET_TYPE_DOUBLE_VALUE:\n return DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET;\n default:\n return undefined;\n }\n }\n\n function getMaxStringLength(packetType: number) {\n switch (packetType) {\n case PACKET_TYPE_STRING:\n return MAX_PAYLOAD_LENGTH - 2;\n case PACKET_TYPE_VALUE:\n case PACKET_TYPE_DOUBLE_VALUE:\n return MAX_FIELD_DOUBLE_NAME_LENGTH;\n default:\n return undefined;\n }\n }\n}",
2046
2046
  "shims.d.ts": "// Auto-generated. Do not edit.\n\n\n\n //% color=#E3008C weight=96 icon=\"\\uf012\"\ndeclare namespace radio {\n\n /**\n * Disables the radio for use as a multipoint sender/receiver.\n * Disabling radio will help conserve battery power when it is not in use.\n */\n //% help=radio/off shim=radio::off\n function off(): void;\n\n /**\n * Initialises the radio for use as a multipoint sender/receiver\n * Only useful when the radio.off() is used beforehand.\n */\n //% help=radio/on shim=radio::on\n function on(): void;\n\n /**\n * Sends an event over radio to neigboring devices\n */\n //% blockId=radioRaiseEvent block=\"radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id\"\n //% blockExternalInputs=1\n //% advanced=true\n //% weight=1\n //% help=radio/raise-event shim=radio::raiseEvent\n function raiseEvent(src: int32, value: int32): void;\n\n /**\n * Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer.\n * @returns NULL if no packet available\n */\n //% shim=radio::readRawPacket\n function readRawPacket(): Buffer;\n\n /**\n * Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet)\n */\n //% async shim=radio::sendRawPacket\n function sendRawPacket(msg: Buffer): void;\n\n /**\n * Used internally by the library.\n */\n //% help=radio/on-data-received\n //% weight=0\n //% blockId=radio_datagram_received_event block=\"radio on data received\" blockGap=8\n //% deprecated=true blockHidden=1 shim=radio::onDataReceived\n function onDataReceived(body: () => void): void;\n\n /**\n * Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.\n * @param id the group id between ``0`` and ``255``, eg: 1\n */\n //% help=radio/set-group\n //% weight=100\n //% blockId=radio_set_group block=\"radio set group %ID\"\n //% id.min=0 id.max=255\n //% group=\"Group\" shim=radio::setGroup\n function setGroup(id: int32): void;\n\n /**\n * Change the output power level of the transmitter to the given value.\n * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. eg: 7\n */\n //% help=radio/set-transmit-power\n //% weight=9 blockGap=8\n //% blockId=radio_set_transmit_power block=\"radio set transmit power %power\"\n //% power.min=0 power.max=7\n //% advanced=true shim=radio::setTransmitPower\n function setTransmitPower(power: int32): void;\n\n /**\n * Change the transmission and reception band of the radio to the given channel\n * @param band a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz.\n **/\n //% help=radio/set-frequency-band\n //% weight=8 blockGap=8\n //% blockId=radio_set_frequency_band block=\"radio set frequency band %band\"\n //% band.min=0 band.max=83\n //% advanced=true shim=radio::setFrequencyBand\n function setFrequencyBand(band: int32): void;\n}\n\n// Auto-generated. Do not edit. Really.\n",
2047
2047
  "targetoverrides.ts": "// leave empty"
2048
2048
  },
2049
2049
  "radio-broadcast": {
2050
- "pxt.json": "{\n \"name\": \"radio-broadcast\",\n \"description\": \"Adds new blocks for message communication in the radio category\",\n \"dependencies\": {\n \"core\": \"*\",\n \"radio\": \"*\"\n },\n \"files\": [\n \"radio-broadcast.ts\"\n ],\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/radio-broadcast.png\"\n}\n",
2050
+ "pxt.json": "{\n \"name\": \"radio-broadcast\",\n \"description\": \"Adds new blocks for message communication in the radio category\",\n \"dependencies\": {\n \"core\": \"*\",\n \"radio\": \"*\"\n },\n \"files\": [\n \"radio-broadcast.ts\"\n ],\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/radio-broadcast.png\"\n}\n",
2051
2051
  "radio-broadcast.ts": "namespace radio {\n const BROADCAST_GENERAL_ID = 2000;\n\n /**\n * Gets the message code\n */\n //% blockHidden=1 shim=ENUM_GET\n //% blockId=radioMessageCode block=\"$msg\" enumInitialMembers=\"message1\"\n //% enumName=RadioMessage enumMemberName=msg enumPromptHint=\"e.g. Start, Stop, Jump...\"\n //% enumIsHash=1\n export function __message(msg: number): number {\n return msg;\n }\n\n /**\n * Broadcasts a message over radio\n * @param msg \n */\n //% blockId=radioBroadcastMessage block=\"radio send $msg\"\n //% msg.shadow=radioMessageCode draggableParameters\n //% weight=200\n //% blockGap=8\n //% help=radio/send-message\n //% group=\"Broadcast\"\n export function sendMessage(msg: number): void {\n // 0 is MICROBIT_EVT_ANY, shifting by 1\n radio.raiseEvent(BROADCAST_GENERAL_ID, msg + 1);\n }\n\n /**\n * Registers code to run for a particular message\n * @param msg \n * @param handler \n */\n //% blockId=radioOnMessageReceived block=\"on radio $msg received\"\n //% msg.shadow=radioMessageCode draggableParameters\n //% weight=199\n //% help=radio/on-received-message\n //% group=\"Broadcast\"\n export function onReceivedMessage(msg: number, handler: () => void) {\n control.onEvent(BROADCAST_GENERAL_ID, msg + 1, handler);\n }\n}"
2052
2052
  },
2053
2053
  "rotary-encoder": {
2054
2054
  "README.md": "# Rotary Encoder\n\n## Configuration\n\nMap the following pins in your bootloader to configure the default \"crank\".\n\n```typescript\nPIN_ROTARY_ENCODER_A\nPIN_ROTARY_ENCODER_B\n```\n",
2055
2055
  "enums.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace encoders {\n}\n\n// Auto-generated. Do not edit. Really.\n",
2056
2056
  "ns.ts": "/**\n * Rotary encoders\n */\n//% color=\"#03AA74\" weight=87 icon=\"\\uf021\"\nnamespace encoders {\n\n /**\n * Gets the default rotary encoder if any\n */\n //% block=\"encoder\" fixedInstance whenUsed\n export const defaultEncoder = encoders.createRotaryEncoder(undefined, undefined);\n}",
2057
- "pxt.json": "{\n \"name\": \"rotary-encoder\",\n \"description\": \"Driver for rotary encoder\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"rotary.cpp\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"README.md\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true,\n \"icon\": \"/static/libs/rotary-encoder.png\"\n}\n",
2057
+ "pxt.json": "{\n \"name\": \"rotary-encoder\",\n \"description\": \"Driver for rotary encoder\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"rotary.cpp\",\n \"enums.d.ts\",\n \"shims.d.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\",\n \"README.md\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true,\n \"icon\": \"/static/libs/rotary-encoder.png\"\n}\n",
2058
2058
  "rotary.cpp": "#include \"pxt.h\"\n\n// update sim if modifying these\n#define ROT_EV_TIMER 0x1233\n#define ROT_EV_CHANGED 0x2233\n\nconst static int8_t posMap[] = {0, +1, -1, +2, -1, 0, -2, +1, +1, -2, 0, -1, +2, -1, +1, 0};\n\nclass RotaryEncoder_ {\n public:\n uint16_t id;\n uint16_t state;\n int position;\n Pin &pinA, &pinB;\n\n void process(Event) {\n // based on comments in https://github.com/PaulStoffregen/Encoder/blob/master/Encoder.h\n uint16_t s = state & 3;\n if (pinA.getDigitalValue())\n s |= 4;\n if (pinB.getDigitalValue())\n s |= 8;\n\n state = (s >> 2);\n if (posMap[s]) {\n int lastPosition = position;\n position += posMap[s];\n if ((lastPosition >> 2) != (position >> 2)) {\n Event ev(id, ROT_EV_CHANGED);\n }\n }\n }\n\n RotaryEncoder_(Pin &pinA, Pin &pinB) : pinA(pinA), pinB(pinB) {\n position = 0;\n id = pinA.id;\n\n pinA.setPull(codal::PullMode::Up);\n pinB.setPull(codal::PullMode::Up);\n\n // don't do exactly 1000us, so that it doesn't occur exactly at scheduler ticks\n system_timer_event_every_us(973, id, ROT_EV_TIMER);\n EventModel::defaultEventBus->listen(id, ROT_EV_TIMER, this, &RotaryEncoder_::process,\n MESSAGE_BUS_LISTENER_IMMEDIATE);\n }\n};\n\ntypedef class RotaryEncoder_ *RotaryEncoder;\n\n/**\n * Rotary and other encoders\n */\nnamespace encoders {\n/**\n * Create a new rotary encoder connected to given pins\n */\n//% weight=99\nRotaryEncoder createRotaryEncoder(DigitalInOutPin pinA, DigitalInOutPin pinB) {\n if (!pinA && !pinB) {\n pinA = LOOKUP_PIN(ROTARY_ENCODER_A);\n pinB = LOOKUP_PIN(ROTARY_ENCODER_B);\n // not configured?\n if (!pinA && !pinB)\n return NULL;\n }\n\n if (!pinA || !pinB)\n target_panic(PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR);\n\n return new RotaryEncoder_(*pinA, *pinB);\n}\n} // namespace pins\n\n//% noRefCounting fixedInstances\nnamespace RotaryEncoderMethods {\n/**\n * Do something when a rotary encoder changes position\n */\n//% blockNamespace=\"encoders\"\n//% blockId=rotaryencoderonchaned block=\"on %this changed\"\n//% weight=80 blockGap=8\nvoid onChanged(RotaryEncoder encoder, Action body) {\n registerWithDal(encoder->id, ROT_EV_CHANGED, body);\n}\n\n/**\n * Get current encoder position.\n */\n//% blockNamespace=\"encoders\"\n//% blockId=rotaryencoderposition block=\"%this position\"\n//% weight=79 blockGap=8\nint position(RotaryEncoder encoder) {\n // the position always changes by 4 per tick\n return encoder->position >> 2;\n}\n\n} // namespace RotaryEncoderMethods\n",
2059
2059
  "shims.d.ts": "// Auto-generated. Do not edit.\n\n\n /**\n * Rotary and other encoders\n */\n\ndeclare namespace encoders {\n\n /**\n * Create a new rotary encoder connected to given pins\n */\n //% weight=99 shim=encoders::createRotaryEncoder\n function createRotaryEncoder(pinA: DigitalInOutPin, pinB: DigitalInOutPin): RotaryEncoder;\n}\n\n\n\n //% noRefCounting fixedInstances\ndeclare interface RotaryEncoder {\n /**\n * Do something when a rotary encoder changes position\n */\n //% blockNamespace=\"encoders\"\n //% blockId=rotaryencoderonchaned block=\"on %this changed\"\n //% weight=80 blockGap=8 shim=RotaryEncoderMethods::onChanged\n onChanged(body: () => void): void;\n\n /**\n * Get current encoder position.\n */\n //% blockNamespace=\"encoders\"\n //% blockId=rotaryencoderposition block=\"%this position\"\n //% weight=79 blockGap=8 shim=RotaryEncoderMethods::position\n position(): int32;\n}\n\n// Auto-generated. Do not edit. Really.\n",
2060
2060
  "targetoverrides.ts": "// target specific\n"
@@ -2070,7 +2070,7 @@ var pxtTargetBundle = {
2070
2070
  "imagesoverrides.ts": "// replace with built-in images",
2071
2071
  "ns.ts": "\n//% color=\"#a5b1c2\"\nnamespace images {\n\n}",
2072
2072
  "panic.cpp": "// potentially overriden in targets",
2073
- "pxt.json": "{\n \"name\": \"screen\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2073
+ "pxt.json": "{\n \"name\": \"screen\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2074
2074
  "pxtparts.json": "{\n \"screen\": {\n \"simulationBehavior\": \"screen\",\n \"visual\": {\n \"builtIn\": \"screen\",\n \"width\": 158.43856811523438,\n \"height\": 146.8025665283203,\n \"pinDistance\": 14.91,\n \"pinLocations\": [\n {\n \"x\": 4.227952701380444,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 18.170226805137037,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 46.05478386015504,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 59.99706238766404,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 73.93934976267785,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 87.88161944268204,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 101.82389797019104,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 32.11250533264604,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 117.68761950246274,\n \"y\": 3.1650031792503945\n }\n ]\n },\n \"numberOfPins\": 9,\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_DC\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_CS\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MOSI\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_SCK\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MISO\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_RST\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"assembly\": [\n {\n \"pinIndices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n 7,\n 8\n ]\n }\n ]\n }\n}",
2075
2075
  "screen.cpp": "// overriden in targets",
2076
2076
  "screenimage.ts": "\nnamespace image {\n /**\n * Get the screen image\n */\n //% blockNamespace=\"images\" group=\"Create\"\n //% blockId=imagescreen block=\"screen\"\n //% help=images/screen-image\n export function screenImage(): Image {\n return screen;\n }\n}\n",
@@ -2089,7 +2089,7 @@ var pxtTargetBundle = {
2089
2089
  "imagesoverrides.ts": "// replace with built-in images",
2090
2090
  "ns.ts": " ",
2091
2091
  "panic.cpp": "// potentially overriden in targets",
2092
- "pxt.json": "{\n \"name\": \"screen---ext\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2092
+ "pxt.json": "{\n \"name\": \"screen---ext\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2093
2093
  "pxtparts.json": "{\n \"screen\": {\n \"simulationBehavior\": \"screen\",\n \"visual\": {\n \"builtIn\": \"screen\",\n \"width\": 158.43856811523438,\n \"height\": 146.8025665283203,\n \"pinDistance\": 14.91,\n \"pinLocations\": [\n {\n \"x\": 4.227952701380444,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 18.170226805137037,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 46.05478386015504,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 59.99706238766404,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 73.93934976267785,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 87.88161944268204,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 101.82389797019104,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 32.11250533264604,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 117.68761950246274,\n \"y\": 3.1650031792503945\n }\n ]\n },\n \"numberOfPins\": 9,\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_DC\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_CS\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MOSI\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_SCK\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MISO\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_RST\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"assembly\": [\n {\n \"pinIndices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n 7,\n 8\n ]\n }\n ]\n }\n}",
2094
2094
  "screen.cpp": "#include \"pxt.h\"\n\nnamespace pxt {\nclass WDisplay {\n public:\n uint32_t currPalette[16];\n bool newPalette, dataWaiting;\n uint8_t *screenBuf;\n\n int width, height;\n\n WDisplay();\n void updateLoop();\n void update(Image_ img);\n};\n\nSINGLETON(WDisplay);\n\nWDisplay::WDisplay() {\n width = getConfig(CFG_DISPLAY_WIDTH, 160);\n height = getConfig(CFG_DISPLAY_HEIGHT, 128);\n DMESG(\"init display: %dx%d\", width, height);\n screenBuf = new uint8_t[width * height / 2 + 20];\n newPalette = false;\n}\n\n//% expose\nint setScreenBrightnessSupported() {\n return 0;\n}\n\n//% expose\nvoid setScreenBrightness(int level) {\n // TODO\n}\n\n//% expose\nvoid setPalette(Buffer buf) {\n auto display = getWDisplay();\n if (48 != buf->length)\n target_panic(PANIC_SCREEN_ERROR);\n for (int i = 0; i < 16; ++i) {\n uint8_t r = buf->data[i * 3];\n uint8_t g = buf->data[i * 3 + 1];\n uint8_t b = buf->data[i * 3 + 2];\n display->currPalette[i] = (0xff << 24) | (r << 16) | (g << 8) | (b << 0);\n }\n display->newPalette = true;\n}\n\nstatic pthread_mutex_t screenMutex;\nstatic pthread_cond_t dataBroadcast;\nstatic int numGetPixels;\n\nDLLEXPORT void pxt_screen_get_pixels(int width, int height, uint32_t *screen) {\n auto disp = instWDisplay;\n numGetPixels++;\n\n if (!disp) {\n int n = width * height;\n uint32_t *p = screen;\n // blue screen\n while (n--)\n *p++ = 0xff000000;\n return;\n }\n\n pthread_mutex_lock(&screenMutex);\n if (!disp->dataWaiting) {\n struct timespec timeout = {0, 100 * 1000 * 1000}; // up to 100ms\n pthread_cond_timedwait(&dataBroadcast, &screenMutex, &timeout);\n }\n if (width != disp->width || height != disp->height)\n target_panic(PANIC_SCREEN_ERROR);\n if (panicCode > 0) {\n int n = width * height;\n uint32_t *p = screen;\n // blue screen\n while (n--)\n *p++ = 0xff0000ff;\n } else {\n auto sp = disp->screenBuf;\n auto pal = disp->currPalette;\n for (int x = 0; x < width; ++x) {\n uint32_t *p = screen + x;\n for (int y = 0; y < (height >> 1); ++y) {\n uint8_t v = *sp++;\n *p = pal[v & 0xf];\n p += width;\n *p = pal[v >> 4];\n p += width;\n }\n }\n }\n pthread_cond_broadcast(&dataBroadcast);\n disp->dataWaiting = false;\n pthread_mutex_unlock(&screenMutex);\n}\n\nvoid WDisplay::update(Image_ img) {\n if (!img)\n return;\n\n if (img->bpp() != 4 || img->width() != width || img->height() != height)\n target_panic(PANIC_SCREEN_ERROR);\n\n pthread_mutex_lock(&screenMutex);\n // if the data have not been picked up, but it had been in the past, wait\n if (dataWaiting && numGetPixels)\n pthread_cond_wait(&dataBroadcast, &screenMutex);\n memcpy(screenBuf, img->pix(), img->pixLength());\n dataWaiting = true;\n pthread_cond_broadcast(&dataBroadcast);\n pthread_mutex_unlock(&screenMutex);\n\n if (newPalette) {\n newPalette = false;\n }\n}\n\n//% expose\nvoid updateScreen(Image_ img) {\n getWDisplay()->update(img);\n}\n\n//% expose\nvoid updateStats(String msg) {\n DMESG(\"stats: %s\", msg->getUTF8Data());\n}\n} // namespace pxt",
2095
2095
  "screenimage.ts": "\nnamespace image {\n /**\n * Get the screen image\n */\n //% blockNamespace=\"images\" group=\"Create\"\n //% blockId=imagescreen block=\"screen\"\n //% help=images/screen-image\n export function screenImage(): Image {\n return screen;\n }\n}\n",
@@ -2108,7 +2108,7 @@ var pxtTargetBundle = {
2108
2108
  "imagesoverrides.ts": "// replace with built-in images",
2109
2109
  "ns.ts": " ",
2110
2110
  "panic.cpp": "// potentially overriden in targets",
2111
- "pxt.json": "{\n \"name\": \"screen---linux\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2111
+ "pxt.json": "{\n \"name\": \"screen---linux\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2112
2112
  "pxtparts.json": "{\n \"screen\": {\n \"simulationBehavior\": \"screen\",\n \"visual\": {\n \"builtIn\": \"screen\",\n \"width\": 158.43856811523438,\n \"height\": 146.8025665283203,\n \"pinDistance\": 14.91,\n \"pinLocations\": [\n {\n \"x\": 4.227952701380444,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 18.170226805137037,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 46.05478386015504,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 59.99706238766404,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 73.93934976267785,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 87.88161944268204,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 101.82389797019104,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 32.11250533264604,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 117.68761950246274,\n \"y\": 3.1650031792503945\n }\n ]\n },\n \"numberOfPins\": 9,\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_DC\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_CS\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MOSI\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_SCK\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MISO\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_RST\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"assembly\": [\n {\n \"pinIndices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n 7,\n 8\n ]\n }\n ]\n }\n}",
2113
2113
  "screen.cpp": "#include \"pxt.h\"\n#include \"pins.h\"\n\n#include <stdlib.h>\n#include <unistd.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <linux/fb.h>\n#include <linux/kd.h>\n#include <sys/mman.h>\n#include <sys/ioctl.h>\n#include <pthread.h>\n\nnamespace pxt {\nclass WDisplay {\n public:\n uint32_t currPalette[16];\n bool newPalette;\n volatile bool painted;\n volatile bool dirty;\n\n uint8_t *screenBuf;\n Image_ lastImg;\n\n int width, height;\n\n int fb_fd;\n uint32_t *fbuf;\n struct fb_fix_screeninfo finfo;\n struct fb_var_screeninfo vinfo;\n\n int eventId;\n\n int is32Bit;\n\n pthread_mutex_t mutex;\n\n WDisplay();\n void updateLoop();\n void update(Image_ img);\n};\n\nSINGLETON(WDisplay);\n\nstatic void *updateDisplay(void *wd) {\n ((WDisplay *)wd)->updateLoop();\n return NULL;\n}\n\nvoid WDisplay::updateLoop() {\n int cur_page = 1;\n int frameNo = 0;\n int numPages = vinfo.yres_virtual / vinfo.yres;\n int ledScreen = getConfigInt(\"LED_SCREEN\", 0);\n\n int sx = vinfo.xres / width;\n int sy = vinfo.yres / height;\n\n if (ledScreen)\n sx = ledScreen;\n\n if (sx > sy)\n sx = sy;\n else\n sy = sx;\n\n if (sx > 1)\n sx &= ~1;\n\n int offx = (vinfo.xres - width * sx) / 2;\n int offy = (vinfo.yres - height * sy) / 2;\n\n if (ledScreen) {\n offx = getConfigInt(\"LED_SCREEN_X\", 0);\n offy = getConfigInt(\"LED_SCREEN_Y\", 0);\n }\n\n int screensize = finfo.line_length * vinfo.yres;\n uint32_t skip = offx;\n\n if (sx > 1)\n offx &= ~1;\n\n DMESG(\"sx=%d sy=%d ox=%d oy=%d 32=%d\", sx, sy, offx, offy, is32Bit);\n DMESG(\"fbuf=%p sz:%d\", fbuf, screensize);\n memset(fbuf, 0x00, screensize * numPages);\n\n if (numPages == 1)\n cur_page = 0;\n\n dirty = true;\n\n DMESG(\"loop\");\n\n for (;;) {\n auto start0 = current_time_us();\n\n while (!dirty)\n sleep_core_us(2000);\n\n // auto start = current_time_us();\n // DMESG(\"update\");\n\n pthread_mutex_lock(&mutex);\n dirty = false;\n\n if (!is32Bit) {\n uint16_t *dst =\n (uint16_t *)fbuf + cur_page * screensize / 2 + offx + offy * finfo.line_length / 2;\n if (sx == 1 && sy == 1) {\n skip = vinfo.xres - width * sx;\n for (int yy = 0; yy < height; yy++) {\n auto shift = yy & 1 ? 4 : 0;\n auto src = screenBuf + yy / 2;\n for (int xx = 0; xx < width; ++xx) {\n int c = this->currPalette[(*src >> shift) & 0xf];\n src += height / 2;\n *dst++ = c;\n }\n dst += skip;\n }\n } else {\n uint32_t *d2 = (uint32_t *)dst;\n for (int yy = 0; yy < height; yy++) {\n auto shift = yy & 1 ? 4 : 0;\n for (int i = 0; i < sy; ++i) {\n auto src = screenBuf + yy / 2;\n for (int xx = 0; xx < width; ++xx) {\n int c = this->currPalette[(*src >> shift) & 0xf];\n src += height / 2;\n for (int j = 0; j < sx / 2; ++j)\n *d2++ = c;\n }\n d2 += skip;\n }\n }\n }\n } else {\n uint32_t *d2 =\n (uint32_t *)fbuf + cur_page * screensize / 4 + offx + offy * finfo.line_length / 4;\n skip = vinfo.xres - width * sx;\n for (int yy = 0; yy < height; yy++) {\n auto shift = yy & 1 ? 4 : 0;\n for (int i = 0; i < sy; ++i) {\n auto src = screenBuf + yy / 2;\n for (int xx = 0; xx < width; ++xx) {\n int c = this->currPalette[(*src >> shift) & 0xf];\n src += height / 2;\n for (int j = 0; j < sx; ++j)\n *d2++ = c;\n }\n d2 += skip;\n }\n }\n }\n\n pthread_mutex_unlock(&mutex);\n\n // auto len = current_time_us() - start;\n\n painted = true;\n raiseEvent(DEVICE_ID_NOTIFY_ONE, eventId);\n\n vinfo.yoffset = cur_page * vinfo.yres;\n ioctl(fb_fd, FBIOPAN_DISPLAY, &vinfo);\n ioctl(fb_fd, FBIO_WAITFORVSYNC, 0);\n if (numPages > 1)\n cur_page = !cur_page;\n frameNo++;\n\n auto fulllen = current_time_us() - start0;\n // throttle it to 40fps (really 30fps)\n if (fulllen < 25000) {\n ioctl(fb_fd, FBIO_WAITFORVSYNC, 0);\n }\n\n // auto tot = current_time_us() - start;\n // if (frameNo % 37 == 0)\n // DMESG(\"copy %d us, tot %d us delay %d us\", (int)len, (int)tot, (int)(start-start0));\n }\n}\n\nWDisplay::WDisplay() {\n pthread_mutex_init(&mutex, NULL);\n\n width = getConfig(CFG_DISPLAY_WIDTH, 160);\n height = getConfig(CFG_DISPLAY_HEIGHT, 128);\n screenBuf = new uint8_t[width * height / 2 + 20];\n lastImg = NULL;\n newPalette = false;\n\n registerGC((TValue *)&lastImg);\n\n eventId = allocateNotifyEvent();\n\n int tty_fd = open(\"/dev/tty0\", O_RDWR);\n ioctl(tty_fd, KDSETMODE, KD_GRAPHICS);\n\n fb_fd = open(\"/dev/fb0\", O_RDWR);\n\n if (fb_fd < 0)\n target_panic(PANIC_SCREEN_ERROR);\n\n ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);\n ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);\n\n DMESG(\"FB: %s at %dx%d %dx%d bpp=%d\", finfo.id, vinfo.xres, vinfo.yres, vinfo.xres_virtual,\n vinfo.yres_virtual, vinfo.bits_per_pixel);\n\n vinfo.yres_virtual = vinfo.yres * 2;\n vinfo.xres_virtual = vinfo.xres;\n\n if (vinfo.bits_per_pixel == 32) {\n is32Bit = true;\n } else {\n vinfo.bits_per_pixel = 16;\n is32Bit = false;\n }\n\n ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vinfo);\n ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);\n ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);\n\n DMESG(\"FB: %s at %dx%d %dx%d bpp=%d %d\", finfo.id, vinfo.xres, vinfo.yres, vinfo.xres_virtual,\n vinfo.yres_virtual, vinfo.bits_per_pixel, finfo.line_length);\n\n fbuf = (uint32_t *)mmap(0, finfo.line_length * vinfo.yres_virtual, PROT_READ | PROT_WRITE,\n MAP_SHARED, fb_fd, (off_t)0);\n\n pthread_t upd;\n pthread_create(&upd, NULL, updateDisplay, this);\n pthread_detach(upd);\n}\n\n//%\nint setScreenBrightnessSupported() {\n return 0;\n}\n\n//%\nvoid setScreenBrightness(int level) {\n // TODO\n}\n\n//%\nvoid setPalette(Buffer buf) {\n auto display = getWDisplay();\n if (48 != buf->length)\n target_panic(PANIC_SCREEN_ERROR);\n for (int i = 0; i < 16; ++i) {\n uint8_t r = buf->data[i * 3];\n uint8_t g = buf->data[i * 3 + 1];\n uint8_t b = buf->data[i * 3 + 2];\n if (display->is32Bit) {\n display->currPalette[i] = (r << 16) | (g << 8) | (b << 0);\n } else {\n r >>= 3;\n g >>= 2;\n b >>= 3;\n uint16_t cc = (r << 11) | (g << 5) | (b << 0);\n display->currPalette[i] = (cc << 16) | cc;\n }\n }\n display->newPalette = true;\n}\n\nvoid WDisplay::update(Image_ img) {\n if (img && img != lastImg) {\n lastImg = img;\n }\n img = lastImg;\n\n if (img) {\n if (img->bpp() != 4 || img->width() != width || img->height() != height)\n target_panic(PANIC_SCREEN_ERROR);\n\n if (!painted) {\n // race is possible (though very unlikely), but in such case we just\n // wait for next frame paint\n waitForEvent(DEVICE_ID_NOTIFY, eventId);\n }\n painted = false;\n\n pthread_mutex_lock(&mutex);\n dirty = true;\n if (newPalette) {\n newPalette = false;\n }\n memcpy(screenBuf, img->pix(), img->pixLength());\n pthread_mutex_unlock(&mutex);\n }\n}\n\n//%\nvoid updateScreen(Image_ img) {\n getWDisplay()->update(img);\n}\n\n//%\nvoid updateStats(String msg) {\n // DMESG(\"render: %s\", msg->data);\n}\n} // namespace pxt",
2114
2114
  "screenimage.ts": "\nnamespace image {\n /**\n * Get the screen image\n */\n //% blockNamespace=\"images\" group=\"Create\"\n //% blockId=imagescreen block=\"screen\"\n //% help=images/screen-image\n export function screenImage(): Image {\n return screen;\n }\n}\n",
@@ -2133,7 +2133,7 @@ var pxtTargetBundle = {
2133
2133
  "jdprotocol.h": "#ifndef __JDPROTOCOL_H\n#define __JDPROTOCOL_H\n\n#include <stdint.h>\n#include <stdbool.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// 255 minus size of the serial header, rounded down to 4\n#define JD_SERIAL_PAYLOAD_SIZE 236\n#define JD_SERIAL_FULL_HEADER_SIZE 16\n\n#define JD_SERVICE_CLASS_CTRL 0x00000000\n\n#define JD_SERVICE_NUMBER_CTRL 0x00\n#define JD_SERVICE_NUMBER_MASK 0x3f\n#define JD_SERVICE_NUMBER_CRC_ACK 0x3f\n\n// the COMMAND flag signifies that the device_identifier is the recipent\n// (i.e., it's a command for the peripheral); the bit clear means device_identifier is the source\n// (i.e., it's a report from peripheral or a broadcast message)\n#define JD_FRAME_FLAG_COMMAND 0x01\n// an ACK should be issued with CRC of this package upon reception\n#define JD_FRAME_FLAG_ACK_REQUESTED 0x02\n// the device_identifier contains target service class number\n#define JD_FRAME_FLAG_IDENTIFIER_IS_SERVICE_CLASS 0x04\n\n#define JD_FRAME_SIZE(pkt) ((pkt)->size + 12)\n\n// Registers 0x001-0x07f - r/w common to all services\n// Registers 0x080-0x0ff - r/w defined per-service\n// Registers 0x100-0x17f - r/o common to all services\n// Registers 0x180-0x1ff - r/o defined per-service\n// Registers 0x200-0xeff - custom, defined per-service\n// Registers 0xf00-0xfff - reserved for implementation, should not be on the wire\n\n// this is either binary (0 or non-zero), or can be gradual (eg. brightness of neopixel)\n#define JD_REG_INTENSITY 0x01\n// the primary value of actuator (eg. servo angle)\n#define JD_REG_VALUE 0x02\n// enable/disable streaming\n#define JD_REG_IS_STREAMING 0x03\n// streaming interval in miliseconds\n#define JD_REG_STREAMING_INTERVAL 0x04\n// for analog sensors\n#define JD_REG_LOW_THRESHOLD 0x05\n#define JD_REG_HIGH_THRESHOLD 0x06\n// limit power drawn; in mA\n#define JD_REG_MAX_POWER 0x07\n\n// eg. one number for light sensor, all 3 coordinates for accelerometer\n#define JD_REG_READING 0x101\n\n#define JD_CMD_GET_REG 0x1000\n#define JD_CMD_SET_REG 0x2000\n\n#define JD_GET(reg) (JD_CMD_GET_REG | (reg))\n#define JD_SET(reg) (JD_CMD_SET_REG | (reg))\n\n// Commands 0x000-0x07f - common to all services\n// Commands 0x080-0xeff - defined per-service\n// Commands 0xf00-0xfff - reserved for implementation\n// enumeration data for CTRL, ad-data for other services\n#define JD_CMD_ADVERTISEMENT_DATA 0x00\n// event from sensor or on broadcast service\n#define JD_CMD_EVENT 0x01\n// request to calibrate sensor\n#define JD_CMD_CALIBRATE 0x02\n// request human-readable description of service\n#define JD_CMD_GET_DESCRIPTION 0x03\n\n// Commands specific to control service\n// do nothing\n#define JD_CMD_CTRL_NOOP 0x80\n// blink led or otherwise draw user's attention\n#define JD_CMD_CTRL_IDENTIFY 0x81\n// reset device\n#define JD_CMD_CTRL_RESET 0x82\n// identifies the type of hardware (eg., ACME Corp. Servo X-42 Rev C)\n#define JD_REG_CTRL_DEVICE_DESCRIPTION 0x180\n// a numeric code for the string above; used to mark firmware images\n#define JD_REG_CTRL_DEVICE_CLASS 0x181\n// MCU temperature in Celsius\n#define JD_REG_CTRL_TEMPERATURE 0x182\n// this is very approximate; ADC reading from backward-biasing the identification LED\n#define JD_REG_CTRL_LIGHT_LEVEL 0x183\n// typically the same as JD_REG_CTRL_DEVICE_CLASS; the bootloader will respond to that code\n#define JD_REG_CTRL_BL_DEVICE_CLASS 0x184\n\nstruct _jd_packet_t {\n uint16_t crc;\n uint8_t _size; // of frame data[]\n uint8_t flags;\n\n uint64_t device_identifier;\n\n uint8_t service_size;\n uint8_t service_number;\n uint16_t service_command;\n\n uint8_t data[0];\n} __attribute__((__packed__, aligned(4)));\ntypedef struct _jd_packet_t jd_packet_t;\n\nstruct _jd_frame_t {\n uint16_t crc;\n uint8_t size;\n uint8_t flags;\n\n uint64_t device_identifier;\n\n uint8_t data[JD_SERIAL_PAYLOAD_SIZE + 4];\n} __attribute__((__packed__, aligned(4)));\ntypedef struct _jd_frame_t jd_frame_t;\n\n#define JDSPI_MAGIC 0x7ACD\n#define JDSPI_MAGIC_NOOP 0xB3CD\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n",
2134
2134
  "ns.ts": "\n//% color=\"#a5b1c2\"\nnamespace images {\n\n}",
2135
2135
  "panic.cpp": "#include \"pxt.h\"\n\n// This adds about 1.2k of binary size, but allows for displaying\n// panic codes regardless of heap state etc. with IRQs disabled.\n\n#define ST7735_NOP 0x00\n#define ST7735_SWRESET 0x01\n#define ST7735_RDDID 0x04\n#define ST7735_RDDST 0x09\n\n#define ST7735_SLPIN 0x10\n#define ST7735_SLPOUT 0x11\n#define ST7735_PTLON 0x12\n#define ST7735_NORON 0x13\n\n#define ST7735_INVOFF 0x20\n#define ST7735_INVON 0x21\n#define ST7735_DISPOFF 0x28\n#define ST7735_DISPON 0x29\n#define ST7735_CASET 0x2A\n#define ST7735_RASET 0x2B\n#define ST7735_RAMWR 0x2C\n#define ST7735_RAMRD 0x2E\n\n#define ST7735_PTLAR 0x30\n#define ST7735_COLMOD 0x3A\n#define ST7735_MADCTL 0x36\n\n#define ST7735_FRMCTR1 0xB1\n#define ST7735_FRMCTR2 0xB2\n#define ST7735_FRMCTR3 0xB3\n#define ST7735_INVCTR 0xB4\n\n#define ST7735_GMCTRP1 0xE0\n#define ST7735_GMCTRN1 0xE1\n\n#define MADCTL_MY 0x80\n#define MADCTL_MX 0x40\n#define MADCTL_MV 0x20\n#define MADCTL_ML 0x10\n#define MADCTL_RGB 0x00\n#define MADCTL_BGR 0x08\n#define MADCTL_MH 0x04\n\nnamespace _pxt_panic {\n\n// target_panic has been called\nstatic bool panicMode = false;\n\n#define DELAY 0x80\n\nclass ST7735 {\n Pin *sck, *mosi, *dc, *cs;\n\n void sendBytes(uint8_t *ptr, uint32_t len);\n void sendCmd(uint8_t *buf, int len);\n void sendCmdSeq(const uint8_t *buf);\n void configure(uint8_t madctl, uint32_t frmctr1);\n\n public:\n uint16_t width, height;\n void fill(int color, int numpixels);\n void setAddrWindow(int x, int y, int w, int h);\n void init();\n void drawNumber(int idx, int x, int y, int color);\n};\n\n// clang-format off\nstatic const uint8_t initCmds[] = {\n ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay\n 120, // 150 ms delay\n ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay\n 120, // 500 ms delay\n ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay\n ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay:\n 0x03, // 12-bit color\n\n ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay\n 10, // 10 ms delay\n ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay\n 10,\n 0, 0 // END\n};\n// clang-format on\n\nstatic const uint8_t numbers[] = {\n 0x06, 0x09, 0x09, 0x09, 0x06, // 0\n 0x04, 0x06, 0x04, 0x04, 0x0e, // 1\n 0x07, 0x08, 0x06, 0x01, 0x0f, // 2\n 0x0f, 0x08, 0x04, 0x09, 0x06, // 3\n 0x0c, 0x0a, 0x09, 0x1f, 0x08, // 4\n 0x1f, 0x01, 0x0f, 0x10, 0x0f, // 5\n 0x08, 0x04, 0x0e, 0x11, 0x0e, // 6\n 0x1f, 0x08, 0x04, 0x02, 0x01, // 7\n 0x0e, 0x11, 0x0e, 0x11, 0x0e, // 8\n 0x0e, 0x11, 0x0e, 0x04, 0x02, // 9\n 0x11, 0x00, 0x0e, 0x1b, 0x11, // :(\n // 0x11, 0x04, 0x04, 0x0a, 0x11, // :(\n};\n\nvoid ST7735::sendBytes(uint8_t *ptr, uint32_t len) {\n uint8_t mask = 0, b;\n for (;;) {\n if (!mask) {\n if (!len--)\n break;\n mask = 0x80;\n b = *ptr++;\n }\n mosi->setDigitalValue((b & mask) ? 1 : 0);\n sck->setDigitalValue(1);\n mask >>= 1;\n sck->setDigitalValue(0);\n }\n}\n\nvoid ST7735::fill(int color, int numpixels) {\n uint8_t cmd[20] = {ST7735_RAMWR};\n sendCmd(cmd, 1);\n\n dc->setDigitalValue(1);\n if (cs)\n cs->setDigitalValue(0);\n\n cmd[0] = color >> 4;\n cmd[1] = (color << 4) | (color >> 8);\n cmd[2] = color;\n\n int n = (numpixels + 1) >> 1;\n while (n--) {\n sendBytes(cmd, 3);\n }\n\n if (cs)\n cs->setDigitalValue(1);\n}\n\nvoid ST7735::sendCmd(uint8_t *buf, int len) {\n // make sure cmd isn't on stack\n dc->setDigitalValue(0);\n if (cs)\n cs->setDigitalValue(0);\n sendBytes(buf, 1);\n dc->setDigitalValue(1);\n len--;\n buf++;\n if (len > 0)\n sendBytes(buf, len);\n if (cs)\n cs->setDigitalValue(1);\n}\n\nstatic void busy_wait_us(int ms) {\n target_wait_us(ms);\n /*\n // this is for 120MHz\n while (ms--) {\n for (int i = 0; i < 30; ++i)\n asm volatile(\"nop\");\n }\n */\n}\n\nvoid ST7735::sendCmdSeq(const uint8_t *buf) {\n uint8_t cmdBuf[32];\n\n while (*buf) {\n cmdBuf[0] = *buf++;\n int v = *buf++;\n int len = v & ~DELAY;\n // note that we have to copy to RAM\n memcpy(cmdBuf + 1, buf, len);\n sendCmd(cmdBuf, len + 1);\n buf += len;\n if (v & DELAY) {\n busy_wait_us(1000 * *buf++);\n }\n }\n}\n\nvoid ST7735::setAddrWindow(int x, int y, int w, int h) {\n w += x - 1;\n h += y - 1;\n uint8_t cmd0[] = {ST7735_RASET, 0, (uint8_t)x, (uint8_t)(w >> 8), (uint8_t)w};\n uint8_t cmd1[] = {ST7735_CASET, 0, (uint8_t)y, (uint8_t)(h >> 8), (uint8_t)h};\n sendCmd(cmd1, sizeof(cmd1));\n sendCmd(cmd0, sizeof(cmd0));\n}\n\nvoid ST7735::init() {\n mosi = LOOKUP_PIN(DISPLAY_MOSI);\n sck = LOOKUP_PIN(DISPLAY_SCK);\n cs = LOOKUP_PIN(DISPLAY_CS);\n dc = LOOKUP_PIN(DISPLAY_DC);\n auto bl = LOOKUP_PIN(DISPLAY_BL);\n auto rst = LOOKUP_PIN(DISPLAY_RST);\n\n if (cs)\n cs->setDigitalValue(1);\n dc->setDigitalValue(1);\n\n if (bl) {\n bl->setDigitalValue(1);\n }\n\n if (rst) {\n rst->setDigitalValue(0);\n busy_wait_us(20 * 1000);\n rst->setDigitalValue(1);\n busy_wait_us(20 * 1000);\n }\n\n uint32_t cfg0 = getConfig(CFG_DISPLAY_CFG0, 0x40);\n uint32_t frmctr1 = getConfig(CFG_DISPLAY_CFG1, 0x000603);\n auto madctl = cfg0 & 0xff;\n\n sendCmdSeq(initCmds);\n configure(madctl, frmctr1);\n\n width = getConfig(CFG_DISPLAY_WIDTH, 160);\n height = getConfig(CFG_DISPLAY_HEIGHT, 128);\n}\n\nvoid ST7735::configure(uint8_t madctl, uint32_t frmctr1) {\n uint8_t cmd0[] = {ST7735_MADCTL, madctl};\n uint8_t cmd1[] = {ST7735_FRMCTR1, (uint8_t)(frmctr1 >> 16), (uint8_t)(frmctr1 >> 8),\n (uint8_t)frmctr1};\n sendCmd(cmd0, sizeof(cmd0));\n sendCmd(cmd1, cmd1[3] == 0xff ? 3 : 4);\n}\n\n#define SIZE 4\n\nvoid ST7735::drawNumber(int idx, int x, int y, int color) {\n const uint8_t *src = &numbers[idx * 5];\n for (int i = 0; i < 5; i++) {\n uint8_t ch = *src++;\n for (int j = 0; j < 5; j++) {\n if (ch & (1 << j)) {\n setAddrWindow(x + j * SIZE, y + i * SIZE, SIZE - 1, SIZE - 1);\n fill(color, (SIZE - 1) * (SIZE - 1));\n }\n }\n }\n}\n\nstatic void drawPanic(int code) {\n if (!LOOKUP_PIN(DISPLAY_MOSI))\n return;\n\n ST7735 display;\n\n display.init();\n display.setAddrWindow(0, 0, display.width, display.height);\n display.fill(0, display.width * display.height);\n\n display.drawNumber(10, 70, 20, 0xf00);\n int x = 50;\n int y = 60;\n display.drawNumber((code / 100) % 10, x, y, 0xff0);\n x += 24;\n display.drawNumber((code / 10) % 10, x, y, 0xff0);\n x += 24;\n display.drawNumber((code / 1) % 10, x, y, 0xff0);\n x += 24;\n}\n\nextern \"C\" __attribute__((weak)) void platform_panic(int statusCode) {}\n\nextern \"C\" void target_panic(int statusCode) {\n __disable_irq(); // low-level disable\n target_disable_irq(); // make sure they stay disabled in DMESG()\n\n DMESG(\"*** CODAL PANIC : [%d]\", statusCode);\n\n __disable_irq(); // disable IRQ after DMESG() again just to make sure\n\n if (panicMode) {\n // avoid recursive panic invocation\n while (1) {\n }\n }\n\n gcFreeze();\n\n // remember first panic code\n panicMode = true;\n\n drawPanic(statusCode);\n\n platform_panic(statusCode);\n\n auto led = LOOKUP_PIN(LED);\n\n const int unit = 100000;\n const int dit = unit;\n const int dat = 3 * unit;\n const int intra = unit;\n const int inter = 2 * unit;\n const int word = 6 * unit;\n while (1) {\n if (led) {\n // SOS\n // . . .\n for (int i = 0; i < 3; ++i) {\n led->setDigitalValue(1);\n busy_wait_us(dit);\n led->setDigitalValue(0);\n busy_wait_us(intra);\n }\n // inter character space\n busy_wait_us(inter);\n // - - -\n for (int i = 0; i < 3; ++i) {\n led->setDigitalValue(1);\n busy_wait_us(dat);\n led->setDigitalValue(0);\n busy_wait_us(intra);\n }\n // inter character space\n busy_wait_us(inter);\n // . . .\n for (int i = 0; i < 3; ++i) {\n led->setDigitalValue(1);\n busy_wait_us(dit);\n led->setDigitalValue(0);\n busy_wait_us(intra);\n }\n // inter character space\n busy_wait_us(word);\n }\n }\n}\n\n} // namespace _pxt_panic",
2136
- "pxt.json": "{\n \"name\": \"screen---st7735\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\",\n \"jdprotocol.h\",\n \"arcadegamepad.h\",\n \"indexedscreen.h\",\n \"arcadesound.h\",\n \"jddisplay.h\",\n \"jddisplay.cpp\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2136
+ "pxt.json": "{\n \"name\": \"screen---st7735\",\n \"description\": \"The screen library\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"screen.cpp\",\n \"panic.cpp\",\n \"image.cpp\",\n \"image.ts\",\n \"screenimage.ts\",\n \"text.ts\",\n \"frame.ts\",\n \"shims.d.ts\",\n \"fieldeditors.ts\",\n \"targetoverrides.ts\",\n \"ns.ts\",\n \"image.d.ts\",\n \"pxtparts.json\",\n \"imagesoverrides.jres\",\n \"imagesoverrides.ts\",\n \"font12.jres\",\n \"jdprotocol.h\",\n \"arcadegamepad.h\",\n \"indexedscreen.h\",\n \"arcadesound.h\",\n \"jddisplay.h\",\n \"jddisplay.cpp\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2137
2137
  "pxtparts.json": "{\n \"screen\": {\n \"simulationBehavior\": \"screen\",\n \"visual\": {\n \"builtIn\": \"screen\",\n \"width\": 158.43856811523438,\n \"height\": 146.8025665283203,\n \"pinDistance\": 14.91,\n \"pinLocations\": [\n {\n \"x\": 4.227952701380444,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 18.170226805137037,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 46.05478386015504,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 59.99706238766404,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 73.93934976267785,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 87.88161944268204,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 101.82389797019104,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 32.11250533264604,\n \"y\": 3.1650031792503945\n },\n {\n \"x\": 117.68761950246274,\n \"y\": 3.1650031792503945\n }\n ]\n },\n \"numberOfPins\": 9,\n \"instantiation\": {\n \"kind\": \"singleton\"\n },\n \"pinDefinitions\": [\n {\n \"target\": \"ground\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_DC\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_CS\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MOSI\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_SCK\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_MISO\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"DISPLAY_RST\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n },\n {\n \"target\": \"threeVolt\",\n \"style\": \"male\",\n \"orientation\": \"-Z\"\n }\n ],\n \"assembly\": [\n {\n \"pinIndices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n 7,\n 8\n ]\n }\n ]\n }\n}",
2138
2138
  "screen.cpp": "#include \"pxt.h\"\n#include \"ST7735.h\"\n#include \"ILI9341.h\"\n\n#include \"SPIScreenIO.h\"\n#ifdef STM32F4\n#include \"FSMCIO.h\"\n#endif\n\n#include \"jddisplay.h\"\n\nnamespace pxt {\n\nclass WDisplay {\n public:\n ScreenIO *io;\n ST7735 *lcd;\n JDDisplay *smart;\n\n uint32_t currPalette[16];\n bool newPalette;\n bool inUpdate;\n\n uint8_t *screenBuf;\n Image_ lastStatus;\n\n uint16_t width, height;\n uint16_t displayHeight;\n uint8_t offX, offY;\n bool doubleSize;\n uint32_t palXOR;\n\n WDisplay() {\n uint32_t cfg2 = getConfig(CFG_DISPLAY_CFG2, 0x0);\n int conn = cfg2 >> 24;\n\n uint32_t cfg0 = getConfig(CFG_DISPLAY_CFG0, 0x40);\n uint32_t frmctr1 = getConfig(CFG_DISPLAY_CFG1, 0x000603);\n\n int dispTp = getConfig(CFG_DISPLAY_TYPE, DISPLAY_TYPE_ST7735);\n\n doubleSize = false;\n smart = NULL;\n\n auto miso = LOOKUP_PIN(DISPLAY_MISO);\n\n if (dispTp == DISPLAY_TYPE_SMART) {\n dispTp = smartConfigure(&cfg0, &frmctr1, &cfg2);\n }\n\n if (dispTp != DISPLAY_TYPE_SMART)\n miso = NULL; // only JDDisplay needs MISO, otherwise leave free\n\n SPI *spi = NULL;\n if (conn == 0) {\n spi = new CODAL_SPI(*LOOKUP_PIN(DISPLAY_MOSI), *miso, *LOOKUP_PIN(DISPLAY_SCK));\n io = new SPIScreenIO(*spi);\n } else if (conn == 1) {\n#ifdef CODAL_CREATE_PARALLEL_SCREEN_IO\n io = CODAL_CREATE_PARALLEL_SCREEN_IO(cfg2 & 0xffffff, PIN(DISPLAY_MOSI),\n PIN(DISPLAY_MISO));\n#else\n target_panic(PANIC_SCREEN_ERROR);\n#endif\n } else {\n target_panic(PANIC_SCREEN_ERROR);\n }\n\n if (dispTp == DISPLAY_TYPE_ST7735)\n lcd = new ST7735(*io, *LOOKUP_PIN(DISPLAY_CS), *LOOKUP_PIN(DISPLAY_DC));\n else if (dispTp == DISPLAY_TYPE_ILI9341) {\n lcd = new ILI9341(*io, *LOOKUP_PIN(DISPLAY_CS), *LOOKUP_PIN(DISPLAY_DC));\n doubleSize = true;\n } else if (dispTp == DISPLAY_TYPE_SMART) {\n lcd = NULL;\n smart = new JDDisplay(spi, LOOKUP_PIN(DISPLAY_CS), LOOKUP_PIN(DISPLAY_DC));\n } else\n target_panic(PANIC_SCREEN_ERROR);\n\n palXOR = (cfg0 & 0x1000000) ? 0xffffff : 0x000000;\n auto madctl = cfg0 & 0xff;\n offX = (cfg0 >> 8) & 0xff;\n offY = (cfg0 >> 16) & 0xff;\n\n DMESG(\"configure screen: FRMCTR1=%p MADCTL=%p type=%d\", frmctr1, madctl, dispTp);\n\n if (spi) {\n auto freq = (cfg2 & 0xff);\n if (!freq)\n freq = 15;\n spi->setFrequency(freq * 1000000);\n spi->setMode(0);\n auto cs = LOOKUP_PIN(DISPLAY_CS);\n if (cs)\n cs->setDigitalValue(1);\n\n // make sure the SPI peripheral is initialized before toggling reset\n spi->write(0);\n }\n\n auto rst = LOOKUP_PIN(DISPLAY_RST);\n if (rst) {\n rst->setDigitalValue(0);\n fiber_sleep(20);\n rst->setDigitalValue(1);\n fiber_sleep(20);\n }\n\n if (lcd) {\n auto bl = LOOKUP_PIN(DISPLAY_BL);\n if (bl) {\n bl->setDigitalValue(1);\n }\n\n lcd->init();\n lcd->configure(madctl, frmctr1);\n }\n\n width = getConfig(CFG_DISPLAY_WIDTH, 160);\n height = getConfig(CFG_DISPLAY_HEIGHT, 128);\n displayHeight = height;\n setAddrMain();\n DMESG(\"screen: %d x %d, off=%d,%d\", width, height, offX, offY);\n int sz = doubleSize ? (width >> 1) * (height >> 1) : width * height;\n screenBuf = (uint8_t *)app_alloc(sz / 2 + 20);\n\n lastStatus = NULL;\n registerGC((TValue *)&lastStatus);\n inUpdate = false;\n }\n\n uint32_t smartConfigure(uint32_t *cfg0, uint32_t *cfg1, uint32_t *cfg2) {\n uint32_t hc;\n\n DMESG(\"74HC: waiting...\");\n\n // wait while nothing is connected\n for (;;) {\n auto rst = LOOKUP_PIN(DISPLAY_RST);\n if (rst) {\n rst->setDigitalValue(0);\n target_wait_us(10);\n rst->setDigitalValue(1);\n fiber_sleep(3); // in reality we need around 1.2ms\n }\n\n hc = readButtonMultiplexer(17);\n if (hc != 0)\n break;\n\n fiber_sleep(100);\n\n // the device will run without shield when the following is specified in user program:\n // namespace userconfig { export const DISPLAY_CFG0 = 0x02000080 }\n if (*cfg0 & 0x2000000) {\n DMESG(\"74HC: no wait requested\");\n return DISPLAY_TYPE_ST7735;\n }\n }\n\n DMESG(\"74HC: %x\", hc);\n\n // is the line forced up? if so, assume JDDisplay\n if (hc == 0x1FFFF) {\n disableButtonMultiplexer();\n return DISPLAY_TYPE_SMART;\n }\n\n hc = hc >> 1;\n\n // SER pin (or first bit of second HC) is orientation\n if (hc & 0x0010)\n *cfg0 = 0x80;\n else\n *cfg0 = 0x40;\n\n uint32_t configId = (hc & 0xe0) >> 5;\n\n switch (configId) {\n case 1:\n *cfg1 = 0x0603; // ST7735\n break;\n case 2:\n *cfg1 = 0xe14ff; // ILI9163C\n *cfg0 |= 0x08; // BGR colors\n break;\n case 3:\n *cfg1 = 0x0603; // ST7735\n *cfg0 |= 0x1000000; // inverted colors\n break;\n default:\n target_panic(PANIC_SCREEN_ERROR);\n break;\n }\n\n DMESG(\"config type: %d; cfg0=%x cfg1=%x\", configId, *cfg0, *cfg1);\n\n *cfg2 = 32; // Damn the torpedoes! 32MHz\n\n return DISPLAY_TYPE_ST7735;\n }\n\n void setAddrStatus() {\n if (lcd)\n lcd->setAddrWindow(offX, offY + displayHeight, width, height - displayHeight);\n else\n smart->setAddrWindow(offX, offY + displayHeight, width, height - displayHeight);\n }\n void setAddrMain() {\n if (lcd)\n lcd->setAddrWindow(offX, offY, width, displayHeight);\n else\n smart->setAddrWindow(offX, offY, width, displayHeight);\n }\n void waitForSendDone() {\n if (lcd)\n lcd->waitForSendDone();\n else\n smart->waitForSendDone();\n }\n int sendIndexedImage(const uint8_t *src, unsigned width, unsigned height, uint32_t *palette) {\n if (lcd)\n return lcd->sendIndexedImage(src, width, height, palette);\n else\n return smart->sendIndexedImage(src, width, height, palette);\n }\n};\n\nSINGLETON_IF_PIN(WDisplay, DISPLAY_MOSI);\n\n//%\nint setScreenBrightnessSupported() {\n auto display = getWDisplay();\n if (display && display->smart)\n return 1;\n\n auto bl = LOOKUP_PIN(DISPLAY_BL);\n if (!bl)\n return 0;\n#ifdef SAMD51\n if (bl->name == PA06)\n return 0;\n#endif\n#ifdef NRF52_SERIES\n // PWM not implemented yet\n return 0;\n#else\n return 1;\n#endif\n}\n\n//%\nvoid setScreenBrightness(int level) {\n if (level < 0)\n level = 0;\n if (level > 100)\n level = 100;\n\n auto display = getWDisplay();\n if (display && display->smart) {\n display->smart->brightness = level;\n return;\n }\n\n auto bl = LOOKUP_PIN(DISPLAY_BL);\n if (!bl)\n return;\n\n if (level == 0)\n bl->setDigitalValue(0);\n else if (level == 100)\n bl->setDigitalValue(1);\n else {\n if (setScreenBrightnessSupported()) {\n bl->setAnalogPeriodUs(1000);\n bl->setAnalogValue(level * level * 1023 / 10000);\n }\n }\n}\n\n//%\nvoid setPalette(Buffer buf) {\n auto display = getWDisplay();\n if (!display)\n return;\n\n if (48 != buf->length)\n target_panic(PANIC_SCREEN_ERROR);\n for (int i = 0; i < 16; ++i) {\n display->currPalette[i] =\n (buf->data[i * 3] << 16) | (buf->data[i * 3 + 1] << 8) | (buf->data[i * 3 + 2] << 0);\n display->currPalette[i] ^= display->palXOR;\n }\n display->newPalette = true;\n}\n\n//%\nvoid setupScreenStatusBar(int barHeight) {\n auto display = getWDisplay();\n if (!display)\n return;\n if (!display->doubleSize) {\n display->displayHeight = display->height - barHeight;\n display->setAddrMain();\n }\n}\n\n//%\nvoid updateScreenStatusBar(Image_ img) {\n auto display = getWDisplay();\n if (!display)\n return;\n\n if (!img)\n return;\n display->lastStatus = img;\n}\n\n//%\nvoid updateScreen(Image_ img) {\n auto display = getWDisplay();\n if (!display)\n return;\n\n if (display->inUpdate)\n return;\n\n display->inUpdate = true;\n\n auto mult = display->doubleSize ? 2 : 1;\n\n if (img) {\n if (img->bpp() != 4 || img->width() * mult != display->width ||\n img->height() * mult != display->displayHeight)\n target_panic(PANIC_SCREEN_ERROR);\n\n // DMESG(\"wait for done\");\n display->waitForSendDone();\n\n auto palette = display->currPalette;\n\n if (display->newPalette) {\n display->newPalette = false;\n } else {\n // smart mode always sends palette\n if (!display->smart)\n palette = NULL;\n }\n\n memcpy(display->screenBuf, img->pix(), img->pixLength());\n\n // DMESG(\"send\");\n display->sendIndexedImage(display->screenBuf, img->width(), img->height(), palette);\n }\n\n if (display->lastStatus && !display->doubleSize) {\n display->waitForSendDone();\n img = display->lastStatus;\n auto barHeight = display->height - display->displayHeight;\n if (img->bpp() != 4 || barHeight != img->height() || img->width() != display->width)\n target_panic(PANIC_SCREEN_ERROR);\n memcpy(display->screenBuf, img->pix(), img->pixLength());\n display->setAddrStatus();\n display->sendIndexedImage(display->screenBuf, img->width(), img->height(), NULL);\n display->waitForSendDone();\n display->setAddrMain();\n display->lastStatus = NULL;\n }\n\n display->inUpdate = false;\n}\n\n//%\nvoid updateStats(String msg) {\n // ignore...\n}\n\n} // namespace pxt",
2139
2139
  "screenimage.ts": "\nnamespace image {\n /**\n * Get the screen image\n */\n //% blockNamespace=\"images\" group=\"Create\"\n //% blockId=imagescreen block=\"screen\"\n //% help=images/screen-image\n export function screenImage(): Image {\n return screen;\n }\n}\n",
@@ -2143,7 +2143,7 @@ var pxtTargetBundle = {
2143
2143
  },
2144
2144
  "serial": {
2145
2145
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum BaudRate {\n //% block=115200\n BaudRate115200 = 115200,\n //% block=57600\n BaudRate57600 = 57600,\n //% block=38400\n BaudRate38400 = 38400,\n //% block=31250\n BaudRate31250 = 31250,\n //% block=28800\n BaudRate28800 = 28800,\n //% block=19200\n BaudRate19200 = 19200,\n //% block=14400\n BaudRate14400 = 14400,\n //% block=9600\n BaudRate9600 = 9600,\n //% block=4800\n BaudRate4800 = 4800,\n //% block=2400\n BaudRate2400 = 2400,\n //% block=1200\n BaudRate1200 = 1200,\n //% block=300\n BaudRate300 = 300,\n }\n\n\n declare const enum SerialEvent {\n //% block=\"data received\"\n DataReceived = 4, // CODAL_SERIAL_EVT_DATA_RECEIVED\n //% block=\"rx buffer full\"\n RxBufferFull = 3, // CODAL_SERIAL_EVT_RX_FULL\n }\n\n\n declare const enum Delimiters {\n //% block=\"new line (\\n)\"\n NewLine = 10,\n //% block=\",\"\n Comma = 44,\n //% block=\"$\"\n Dollar = 36,\n //% block=\":\"\n Colon = 58,\n //% block=\".\"\n Fullstop = 46,\n //% block=\"#\"\n Hash = 35,\n //% block=\"carriage return (\\r)\"\n CarriageReturn = 13,\n //% block=\"space\"\n Space = 32,\n //% block=\"tab (\\t)\"\n Tab = 9,\n //% block=\"|\"\n Pipe = 124,\n //% block=\";\"\n SemiColon = 59,\n }\n\n// Auto-generated. Do not edit. Really.\n",
2146
- "pxt.json": "{\n \"name\": \"serial\",\n \"description\": \"UART communication\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"serial-target.h\",\n \"serial-common.h\",\n \"serial-target.cpp\",\n \"serial-common.cpp\",\n \"serial-target.ts\",\n \"serial.ts\",\n \"enums.d.ts\",\n \"shims.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2146
+ "pxt.json": "{\n \"name\": \"serial\",\n \"description\": \"UART communication\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"serial-target.h\",\n \"serial-common.h\",\n \"serial-target.cpp\",\n \"serial-common.cpp\",\n \"serial-target.ts\",\n \"serial.ts\",\n \"enums.d.ts\",\n \"shims.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2147
2147
  "serial-common.cpp": "#include \"pxt.h\"\n#include \"serial-target.h\"\n\nnamespace SerialDeviceMethods {\n/**\n * Sets the size of the RX buffer in bytes\n */\n//%\nvoid setRxBufferSize(SerialDevice device, uint8_t size) {\n device->setRxBufferSize(size);\n}\n\n/**\n * Sets the size of the TX buffer in bytes\n */\n//%\nvoid setTxBufferSize(SerialDevice device, uint8_t size) {\n device->setTxBufferSize(size);\n}\n\n/**\nSet the baud rate of the serial port\n*/\n//%\nvoid setBaudRate(SerialDevice device, BaudRate rate) {\n device->setBaudRate((int)rate);\n}\n\n/**\n * Reads a single byte from the serial receive buffer. Negative if error, 0 if no data.\n */\n//%\nint read(SerialDevice device) {\n return device->read();\n}\n\n/**\n * Read the buffered received data as a buffer\n */\n//%\nBuffer readBuffer(SerialDevice device) {\n return device->readBuffer();\n}\n\n/**\n * Send a buffer across the serial connection.\n */\n//%\nvoid writeBuffer(SerialDevice device, Buffer buffer) {\n device->writeBuffer(buffer);\n}\n\n/**\n * Register code when a serial event occurs\n */\n//%\nvoid onEvent(SerialDevice device, SerialEvent event, Action handler) {\n device->onEvent(event, handler);\n}\n\n/**\n * Registers code when a delimiter is received\n **/\n//%\nvoid onDelimiterReceived(SerialDevice device, Delimiters delimiter, Action handler) {\n device->onDelimiterReceived(delimiter, handler);\n}\n} // namespace SerialDeviceMethods\n",
2148
2148
  "serial-common.h": "#pragma once\n#include \"pxt.h\"\n#include \"serial-target.h\"\n\nenum class BaudRate {\n //% block=115200\n BaudRate115200 = 115200,\n //% block=57600\n BaudRate57600 = 57600,\n //% block=38400\n BaudRate38400 = 38400,\n //% block=31250\n BaudRate31250 = 31250,\n //% block=28800\n BaudRate28800 = 28800,\n //% block=19200\n BaudRate19200 = 19200,\n //% block=14400\n BaudRate14400 = 14400,\n //% block=9600\n BaudRate9600 = 9600,\n //% block=4800\n BaudRate4800 = 4800,\n //% block=2400\n BaudRate2400 = 2400,\n //% block=1200\n BaudRate1200 = 1200,\n //% block=300\n BaudRate300 = 300\n};\n\nenum class SerialEvent {\n //% block=\"data received\"\n DataReceived = CODAL_SERIAL_EVT_DATA_RECEIVED,\n //% block=\"rx buffer full\"\n RxBufferFull = CODAL_SERIAL_EVT_RX_FULL\n};\n\nenum class Delimiters {\n //% block=\"new line (\\n)\"\n NewLine = 10,\n //% block=\",\"\n Comma = 44,\n //% block=\"$\"\n Dollar = 36,\n //% block=\":\"\n Colon = 58,\n //% block=\".\"\n Fullstop = 46,\n //% block=\"#\"\n Hash = 35,\n //% block=\"carriage return (\\r)\"\n CarriageReturn = 13,\n //% block=\"space\"\n Space = 32,\n //% block=\"tab (\\t)\"\n Tab = 9,\n //% block=\"|\"\n Pipe = 124,\n //% block=\";\"\n SemiColon = 59,\n};\n\n",
2149
2149
  "serial-target.cpp": "#include \"pxt.h\"\n#include \"serial-target.h\"\n\nnamespace serial {\n\nstatic SerialDevice serialDevices(NULL);\n/**\n * Opens a Serial communication driver\n */\n//%\nSerialDevice internalCreateSerialDevice(DigitalInOutPin tx, DigitalInOutPin rx, int id) {\n auto dev = serialDevices;\n while (dev) {\n if (dev->matchPins(tx, rx))\n return dev;\n dev = dev->next;\n }\n\n // allocate new one\n auto ser = new CodalSerialDeviceProxy(tx, rx, id);\n ser->next = serialDevices;\n serialDevices = ser;\n return ser;\n}\n\n} // namespace serial\n\nnamespace SerialDeviceMethods {\n\n/**\n */\n//%\nvoid redirect(SerialDevice device, DigitalInOutPin tx, DigitalInOutPin rx, BaudRate rate) {\n device->redirect(tx, rx, rate);\n}\n\n} // namespace SerialDeviceMethods\n",
@@ -2155,7 +2155,7 @@ var pxtTargetBundle = {
2155
2155
  },
2156
2156
  "serial---linux": {
2157
2157
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum BaudRate {\n //% block=115200\n BaudRate115200 = 115200,\n //% block=57600\n BaudRate57600 = 57600,\n //% block=38400\n BaudRate38400 = 38400,\n //% block=31250\n BaudRate31250 = 31250,\n //% block=28800\n BaudRate28800 = 28800,\n //% block=19200\n BaudRate19200 = 19200,\n //% block=14400\n BaudRate14400 = 14400,\n //% block=9600\n BaudRate9600 = 9600,\n //% block=4800\n BaudRate4800 = 4800,\n //% block=2400\n BaudRate2400 = 2400,\n //% block=1200\n BaudRate1200 = 1200,\n //% block=300\n BaudRate300 = 300,\n }\n\n\n declare const enum SerialEvent {\n //% block=\"data received\"\n DataReceived = 4, // CODAL_SERIAL_EVT_DATA_RECEIVED\n //% block=\"rx buffer full\"\n RxBufferFull = 3, // CODAL_SERIAL_EVT_RX_FULL\n }\n\n\n declare const enum Delimiters {\n //% block=\"new line (\\n)\"\n NewLine = 10,\n //% block=\",\"\n Comma = 44,\n //% block=\"$\"\n Dollar = 36,\n //% block=\":\"\n Colon = 58,\n //% block=\".\"\n Fullstop = 46,\n //% block=\"#\"\n Hash = 35,\n //% block=\"carriage return (\\r)\"\n CarriageReturn = 13,\n //% block=\"space\"\n Space = 32,\n //% block=\"tab (\\t)\"\n Tab = 9,\n //% block=\"|\"\n Pipe = 124,\n //% block=\";\"\n SemiColon = 59,\n }\n\n// Auto-generated. Do not edit. Really.\n",
2158
- "pxt.json": "{\n \"name\": \"serial---linux\",\n \"description\": \"UART communication\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"serial-target.h\",\n \"serial-common.h\",\n \"serial-target.cpp\",\n \"serial-common.cpp\",\n \"serial-target.ts\",\n \"serial.ts\",\n \"enums.d.ts\",\n \"shims.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2158
+ "pxt.json": "{\n \"name\": \"serial---linux\",\n \"description\": \"UART communication\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"serial-target.h\",\n \"serial-common.h\",\n \"serial-target.cpp\",\n \"serial-common.cpp\",\n \"serial-target.ts\",\n \"serial.ts\",\n \"enums.d.ts\",\n \"shims.d.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2159
2159
  "serial-common.cpp": "#include \"pxt.h\"\n#include \"serial-target.h\"\n\nnamespace SerialDeviceMethods {\n/**\n * Sets the size of the RX buffer in bytes\n */\n//%\nvoid setRxBufferSize(SerialDevice device, uint8_t size) {\n device->setRxBufferSize(size);\n}\n\n/**\n * Sets the size of the TX buffer in bytes\n */\n//%\nvoid setTxBufferSize(SerialDevice device, uint8_t size) {\n device->setTxBufferSize(size);\n}\n\n/**\nSet the baud rate of the serial port\n*/\n//%\nvoid setBaudRate(SerialDevice device, BaudRate rate) {\n device->setBaudRate((int)rate);\n}\n\n/**\n * Reads a single byte from the serial receive buffer. Negative if error, 0 if no data.\n */\n//%\nint read(SerialDevice device) {\n return device->read();\n}\n\n/**\n * Read the buffered received data as a buffer\n */\n//%\nBuffer readBuffer(SerialDevice device) {\n return device->readBuffer();\n}\n\n/**\n * Send a buffer across the serial connection.\n */\n//%\nvoid writeBuffer(SerialDevice device, Buffer buffer) {\n device->writeBuffer(buffer);\n}\n\n/**\n * Register code when a serial event occurs\n */\n//%\nvoid onEvent(SerialDevice device, SerialEvent event, Action handler) {\n device->onEvent(event, handler);\n}\n\n/**\n * Registers code when a delimiter is received\n **/\n//%\nvoid onDelimiterReceived(SerialDevice device, Delimiters delimiter, Action handler) {\n device->onDelimiterReceived(delimiter, handler);\n}\n} // namespace SerialDeviceMethods\n",
2160
2160
  "serial-common.h": "#pragma once\n#include \"pxt.h\"\n#include \"serial-target.h\"\n\nenum class BaudRate {\n //% block=115200\n BaudRate115200 = 115200,\n //% block=57600\n BaudRate57600 = 57600,\n //% block=38400\n BaudRate38400 = 38400,\n //% block=31250\n BaudRate31250 = 31250,\n //% block=28800\n BaudRate28800 = 28800,\n //% block=19200\n BaudRate19200 = 19200,\n //% block=14400\n BaudRate14400 = 14400,\n //% block=9600\n BaudRate9600 = 9600,\n //% block=4800\n BaudRate4800 = 4800,\n //% block=2400\n BaudRate2400 = 2400,\n //% block=1200\n BaudRate1200 = 1200,\n //% block=300\n BaudRate300 = 300\n};\n\nenum class SerialEvent {\n //% block=\"data received\"\n DataReceived = CODAL_SERIAL_EVT_DATA_RECEIVED,\n //% block=\"rx buffer full\"\n RxBufferFull = CODAL_SERIAL_EVT_RX_FULL\n};\n\nenum class Delimiters {\n //% block=\"new line (\\n)\"\n NewLine = 10,\n //% block=\",\"\n Comma = 44,\n //% block=\"$\"\n Dollar = 36,\n //% block=\":\"\n Colon = 58,\n //% block=\".\"\n Fullstop = 46,\n //% block=\"#\"\n Hash = 35,\n //% block=\"carriage return (\\r)\"\n CarriageReturn = 13,\n //% block=\"space\"\n Space = 32,\n //% block=\"tab (\\t)\"\n Tab = 9,\n //% block=\"|\"\n Pipe = 124,\n //% block=\";\"\n SemiColon = 59,\n};\n\n",
2161
2161
  "serial-target.cpp": "#include \"pxt.h\"\n#include \"serial-common.h\"\n\n#include <string.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <stdint.h>\n#include <sys/signal.h>\n#include <sys/types.h>\n#include <termios.h>\n#include <errno.h>\n\n#ifndef SERIAL_DEVICE\n#define SERIAL_DEVICE \"/dev/ttyS0\"\n#endif\n\nnamespace serial {\n/**\n * Opens a Serial communication driver\n */\n//%\nSerialDevice internalCreateSerialDevice(int id) {\n return new LinuxSerialDevice(id);\n}\n\nstruct SerialSpeed {\n int code;\n int speed;\n};\n\nstatic const SerialSpeed serialSpeeds[] = {\n {B50, 50}, {B75, 75}, {B110, 110}, {B134, 134},\n {B150, 150}, {B200, 200}, {B300, 300}, {B600, 600},\n {B1200, 1200}, {B1800, 1800}, {B2400, 2400}, {B4800, 4800},\n {B9600, 9600}, {B19200, 19200}, {B38400, 38400}, {B57600, 57600},\n {B115200, 115200}, {B230400, 230400}, {B460800, 460800}, {B500000, 500000},\n {B576000, 576000}, {B921600, 921600}, {B1000000, 1000000}, {B1152000, 1152000},\n {B1500000, 1500000}, {B2000000, 2000000}, {B2500000, 2500000}, {B3000000, 3000000},\n {B3500000, 3500000}, {B4000000, 4000000}};\n\nvoid LinuxSerialDevice::init() {\n auto serialDev = getConfigString(\"SERIAL_DEVICE\");\n if (!serialDev) {\n char buf[40];\n int fd = open(\"/proc/device-tree/model\", O_RDONLY);\n if (fd >= 0) {\n int len = ::read(fd, buf, sizeof(buf) - 1);\n DMESG(\"device model: %s\", buf);\n if (len > 0) {\n buf[len] = 0;\n if (strstr(buf, \"Raspberry Pi\")) {\n if (strstr(buf, \"Raspberry Pi 3 Model\") || strstr(buf, \"Raspberry Pi Zero W\"))\n serialDev = \"/dev/ttyS0\";\n else\n serialDev = \"/dev/ttyAMA0\";\n }\n }\n close(fd);\n }\n }\n\n if (!serialDev)\n serialDev = SERIAL_DEVICE;\n\n DMESG(\"serial device: %s\", serialDev);\n\n fd = open(serialDev, O_RDWR | O_NOCTTY);\n if (fd < 0)\n target_panic(PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR);\n\n setRxBufferSize(128);\n setBaudRate(115200);\n\n pthread_t pid;\n pthread_create(&pid, NULL, &LinuxSerialDevice::readLoop, this);\n pthread_detach(pid);\n}\n\nvoid *LinuxSerialDevice::readLoop(void *th) {\n ((LinuxSerialDevice *)th)->readLoopInner();\n return NULL;\n}\n\nvoid LinuxSerialDevice::readLoopInner() {\n uint8_t buf[128];\n while (true) {\n pthread_mutex_lock(&lock);\n int left = buffersz - bufferedSize();\n pthread_mutex_unlock(&lock);\n if (left == 0) {\n raiseEvent(id, CODAL_SERIAL_EVT_RX_FULL);\n sleep_core_us(20 * 1000);\n continue;\n }\n if (left > (int)sizeof(buf))\n left = sizeof(buf);\n int r = ::read(fd, buf, left);\n if (r <= 0)\n target_panic(PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR);\n\n pthread_mutex_lock(&lock);\n int chunk = buffersz - writep;\n if (r < chunk)\n chunk = r;\n memcpy(buffer + writep, buf, chunk);\n writep += chunk;\n if (writep == buffersz) {\n writep = 0;\n int r2 = r - chunk;\n if (r2) {\n memcpy(buffer, buf + chunk, r2);\n writep += r2;\n }\n }\n pthread_mutex_unlock(&lock);\n\n raiseEvent(id, CODAL_SERIAL_EVT_DATA_RECEIVED);\n\n if (delim != -1)\n for (int i = 0; i < r; ++i)\n if (buf[i] == delim)\n raiseEvent(id, CODAL_SERIAL_EVT_DELIM_MATCH);\n }\n}\n\nvoid LinuxSerialDevice::setBaudRate(int rate) {\n struct termios tio;\n memset(&tio, 0, sizeof(tio));\n if (tcgetattr(fd, &tio) != 0) {\n target_panic(PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR);\n return;\n }\n\n int speedCode = B115200;\n for (int i = sizeof(serialSpeeds) / sizeof(serialSpeeds[0]); i >= 0; i--) {\n if (serialSpeeds[i].speed <= rate) {\n speedCode = serialSpeeds[i].code;\n DMESG(\"set serial speed: %d->%d\", rate, serialSpeeds[i].speed);\n break;\n }\n }\n\n cfmakeraw(&tio);\n cfsetispeed(&tio, speedCode);\n cfsetospeed(&tio, speedCode);\n\n tio.c_cflag |= CLOCAL | CREAD;\n tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE);\n tio.c_cflag |= CS8;\n tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);\n tio.c_oflag &= ~OPOST;\n\n tio.c_cc[VMIN] = 1; // read blocks\n tio.c_cc[VTIME] = 0; // no intra-character timeout\n\n if (tcsetattr(fd, TCSANOW, &tio) != 0) {\n target_panic(PANIC_CODAL_HARDWARE_CONFIGURATION_ERROR);\n return;\n }\n}\n\nvoid LinuxSerialDevice::setRxBufferSize(unsigned size) {\n pthread_mutex_lock(&lock);\n auto tmp = malloc(size);\n if (buffer) {\n auto bsz = bufferedSize();\n if (bsz > (int)size)\n bsz = size;\n readBuf(tmp, bsz);\n readp = 0;\n writep = bsz;\n free(buffer);\n }\n buffer = (uint8_t *)tmp;\n buffersz = size;\n pthread_mutex_unlock(&lock);\n}\n\nint LinuxSerialDevice::read() {\n pthread_mutex_lock(&lock);\n uint8_t c;\n int r = readBuf(&c, 1);\n pthread_mutex_unlock(&lock);\n if (r)\n return c;\n return -1;\n}\n\nBuffer LinuxSerialDevice::readBuffer() {\n pthread_mutex_lock(&lock);\n int sz = bufferedSize();\n auto r = mkBuffer(NULL, sz);\n registerGCObj(r);\n int sz2 = readBuf(r->data, sz);\n unregisterGCObj(r);\n if (sz != sz2)\n target_panic(999);\n pthread_mutex_unlock(&lock);\n return r;\n}\n\nvoid LinuxSerialDevice::writeBuffer(Buffer buffer) {\n if (NULL == buffer)\n return;\n auto p = buffer->data;\n auto len = buffer->length;\n while (len) {\n int r = write(fd, p, len);\n if (r >= 0) {\n len -= r;\n p += r;\n } else {\n DMESG(\"serial write error: %d / %d\", r, errno);\n break;\n }\n }\n}\n\nint LinuxSerialDevice::readBuf(void *buf, int sz) {\n int amount = bufferedSize();\n if (amount < sz)\n sz = amount;\n if (sz > 0) {\n int chunk = buffersz - readp;\n if (chunk > sz)\n chunk = sz;\n\n memcpy(buf, buffer + readp, chunk);\n readp += chunk;\n if (readp == buffersz)\n readp = 0;\n buf = (uint8_t *)buf + chunk;\n\n if (sz - chunk > 0) {\n memcpy(buf, buffer + readp, sz - chunk);\n readp += chunk;\n }\n }\n return sz;\n}\n\n} // namespace serial\n",
@@ -2168,7 +2168,7 @@ var pxtTargetBundle = {
2168
2168
  "servo": {
2169
2169
  "README.md": "# Servo\n\nA small micro-servo library.",
2170
2170
  "ns.ts": "/**\n * Control micro servos\n */\n//% color=\"#03AA74\" weight=88 icon=\"\\uf021\"\nnamespace servos {\n}",
2171
- "pxt.json": "{\n \"name\": \"servo\",\n \"description\": \"A micro-servo library\",\n \"dependencies\": {\n \"core\": \"*\",\n \"edge-connector\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"servo.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/servo.png\"\n}\n",
2171
+ "pxt.json": "{\n \"name\": \"servo\",\n \"description\": \"A micro-servo library\",\n \"dependencies\": {\n \"core\": \"*\",\n \"edge-connector\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"servo.ts\",\n \"ns.ts\",\n \"targetoverrides.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/servo.png\"\n}\n",
2172
2172
  "servo.ts": "/**\n * Control micro servos\n */\n//% color=\"#03AA74\" weight=88 icon=\"\\uf021\" blockGap=8\n//% groups='[\"Positional\", \"Continuous\", \"Configuration\"]'\nnamespace servos {\n //% fixedInstances\n export class Servo {\n private _minAngle: number;\n private _maxAngle: number;\n private _stopOnNeutral: boolean;\n private _angle: number;\n\n constructor() {\n this._angle = undefined;\n this._minAngle = 0;\n this._maxAngle = 180;\n this._stopOnNeutral = false;\n }\n\n private clampDegrees(degrees: number): number {\n degrees = degrees | 0;\n degrees = Math.clamp(this._minAngle, this._maxAngle, degrees);\n return degrees;\n }\n\n /**\n * Set the servo angle\n */\n //% weight=100 help=servos/set-angle\n //% blockId=servoservosetangle block=\"set %servo angle to %degrees=protractorPicker °\"\n //% degrees.defl=90\n //% servo.fieldEditor=\"gridpicker\"\n //% servo.fieldOptions.width=220\n //% servo.fieldOptions.columns=2\n //% blockGap=8\n //% parts=microservo trackArgs=0\n //% group=\"Positional\"\n setAngle(degrees: number) {\n degrees = this.clampDegrees(degrees);\n this.internalSetContinuous(false);\n this._angle = this.internalSetAngle(degrees);\n }\n\n get angle() {\n return this._angle || 90;\n }\n\n protected internalSetContinuous(continuous: boolean): void {\n\n }\n\n protected internalSetAngle(angle: number): number {\n return 0;\n }\n\n /**\n * Set the throttle on a continuous servo\n * @param speed the throttle of the motor from -100% to 100%\n */\n //% weight=99 help=servos/run\n //% blockId=servoservorun block=\"continuous %servo run at %speed=speedPicker \\\\%\"\n //% servo.fieldEditor=\"gridpicker\"\n //% servo.fieldOptions.width=220\n //% servo.fieldOptions.columns=2\n //% parts=microservo trackArgs=0\n //% group=\"Continuous\"\n //% blockGap=8\n run(speed: number): void {\n const degrees = this.clampDegrees(Math.map(speed, -100, 100, this._minAngle, this._maxAngle));\n const neutral = (this.maxAngle - this.minAngle) >> 1;\n this.internalSetContinuous(true);\n if (this._stopOnNeutral && degrees == neutral)\n this.stop();\n else\n this._angle = this.internalSetAngle(degrees);\n }\n\n /**\n * Set the pulse width to the servo in microseconds\n * @param micros the width of the pulse in microseconds\n */\n\n //% weight=10 help=servos/set-pulse\n //% blockId=servoservosetpulse block=\"set %servo pulse to %micros μs\"\n //% micros.min=500 micros.max=2500\n //% micros.defl=1500\n //% servo.fieldEditor=\"gridpicker\"\n //% servo.fieldOptions.width=220\n //% servo.fieldOptions.columns=2\n //% parts=microservo trackArgs=0\n //% group=\"Configuration\"\n //% blockGap=8\n setPulse(micros: number) {\n micros = micros | 0;\n micros = Math.clamp(500, 2500, micros);\n this.internalSetPulse(micros);\n }\n\n protected internalSetPulse(micros: number): void {\n\n }\n\n /**\n * Stop sending commands to the servo so that its rotation will stop at the current position.\n */\n // On a normal servo this will stop the servo where it is, rather than return it to neutral position.\n // It will also not provide any holding force.\n //% weight=10 help=servos/stop\n //% blockId=servoservostop block=\"stop %servo\"\n //% servo.fieldEditor=\"gridpicker\"\n //% servo.fieldOptions.width=220\n //% servo.fieldOptions.columns=2\n //% parts=microservo trackArgs=0\n //% group=\"Continuous\"\n //% blockGap=8\n stop() {\n if (this._angle !== undefined)\n this.internalStop();\n }\n\n /**\n * Gets the minimum angle for the servo\n */\n public get minAngle() {\n return this._minAngle;\n }\n\n /**\n * Gets the maximum angle for the servo\n */\n public get maxAngle() {\n return this._maxAngle;\n }\n\n /**\n * Set the possible rotation range angles for the servo between 0 and 180\n * @param minAngle the minimum angle from 0 to 90\n * @param maxAngle the maximum angle from 90 to 180\n */\n //% help=servos/set-range\n //% blockId=servosetrange block=\"set %servo range from %minAngle to %maxAngle\"\n //% minAngle.min=0 minAngle.max=90\n //% maxAngle.min=90 maxAngle.max=180 maxAngle.defl=180\n //% servo.fieldEditor=\"gridpicker\"\n //% servo.fieldOptions.width=220\n //% servo.fieldOptions.columns=2\n //% parts=microservo trackArgs=0\n //% group=\"Configuration\"\n //% blockGap=8\n public setRange(minAngle: number, maxAngle: number) {\n this._minAngle = Math.max(0, Math.min(90, minAngle | 0));\n this._maxAngle = Math.max(90, Math.min(180, maxAngle | 0));\n }\n\n /**\n * Set a servo stop mode so it will stop when the rotation angle is in the neutral position, 90 degrees.\n * @param on true to enable this mode\n */\n //% help=servos/set-stop-on-neutral\n //% blockId=servostoponneutral block=\"set %servo stop on neutral %enabled\"\n //% enabled.shadow=toggleOnOff\n //% group=\"Configuration\"\n //% blockGap=8\n //% servo.fieldEditor=\"gridpicker\"\n //% servo.fieldOptions.width=220\n //% servo.fieldOptions.columns=2\n public setStopOnNeutral(enabled: boolean) {\n this._stopOnNeutral = enabled;\n }\n\n protected internalStop() { }\n }\n\n export class PinServo extends Servo {\n private _pin: PwmOnlyPin;\n\n constructor(pin: PwmOnlyPin) {\n super();\n this._pin = pin;\n }\n\n protected internalSetAngle(angle: number): number {\n this._pin.servoWrite(angle);\n return angle;\n }\n\n protected internalSetContinuous(continuous: boolean): void {\n this._pin.servoSetContinuous(continuous);\n }\n\n protected internalSetPulse(micros: number): void {\n this._pin.servoSetPulse(micros);\n }\n\n protected internalStop() {\n this._pin.digitalRead();\n this._pin.setPull(PinPullMode.PullNone);\n }\n }\n}\n",
2173
2173
  "targetoverrides.ts": "namespace servos {\n //% block=\"servo P0\" fixedInstance whenUsed\n export const P0 = new servos.PinServo(pins.P0);\n //% block=\"servo P1\" fixedInstance whenUsed\n export const P1 = new servos.PinServo(pins.P1);\n //% block=\"servo P2\" fixedInstance whenUsed\n export const P2 = new servos.PinServo(pins.P2);\n}"
2174
2174
  },
@@ -2181,24 +2181,24 @@ var pxtTargetBundle = {
2181
2181
  "RP2040Flash.cpp": "#include \"pxt.h\"\n#include \"Flash.h\"\n\n//#define LOG DMESG\n#define LOG NOLOG\n\n#ifdef PICO_BOARD\n#include \"hardware/flash.h\"\n\n#define XIP_BIAS 0x10000000\n\nnamespace codal {\n\nint ZFlash::pageSize(uintptr_t address) {\n return FLASH_SECTOR_SIZE;\n}\n\nint ZFlash::totalSize() {\n#ifndef PICO_FLASH_SIZE_BYTES\n return 2*1024*1024;\n#else\n return PICO_FLASH_SIZE_BYTES;\n#endif\n}\n\nint ZFlash::erasePage(uintptr_t address) {\n // address should be aligned to 4096\n if (address % 4096 == 0){\n target_disable_irq();\n flash_range_erase(address - XIP_BIAS, FLASH_SECTOR_SIZE); \n target_enable_irq();\n }\n return 0;\n}\n\nint ZFlash::writeBytes(uintptr_t dst, const void *src, uint32_t len) {\n if (len != FLASH_PAGE_SIZE || (dst & (FLASH_PAGE_SIZE - 1))) return -1;\n // should be aligned to 256\n target_disable_irq();\n flash_range_program(dst - XIP_BIAS, (const uint8_t*)src, FLASH_PAGE_SIZE);\n target_enable_irq();\n \n return 0;\n}\n\n\n\n\n}\n\n#endif\n",
2182
2182
  "SAMDFlash.cpp": "#include \"pxt.h\"\n#include \"Flash.h\"\n\n//#define LOG DMESG\n#define LOG NOLOG\n\n#if defined(SAMD51) || defined(SAMD21)\nnamespace codal {\n\n#ifdef SAMD51\n#define waitForLast() \\\n while (NVMCTRL->STATUS.bit.READY == 0) \\\n ;\n#else\n#define waitForLast() \\\n while (NVMCTRL->INTFLAG.bit.READY == 0) \\\n ;\n#endif\n\nstatic void unlock() {\n#ifdef SAMD51\n // see errata 2.14.1\n NVMCTRL->CTRLA.bit.CACHEDIS0 = true;\n NVMCTRL->CTRLA.bit.CACHEDIS1 = true;\n\n CMCC->CTRL.bit.CEN = 0;\n while (CMCC->SR.bit.CSTS) {\n }\n CMCC->MAINT0.bit.INVALL = 1;\n#endif\n}\n\nstatic void lock() {\n#ifdef SAMD51\n // re-enable cache\n NVMCTRL->CTRLA.bit.CACHEDIS0 = false;\n NVMCTRL->CTRLA.bit.CACHEDIS1 = false;\n\n // re-enable cortex-m cache - it's a separate one\n CMCC->CTRL.bit.CEN = 0;\n while (CMCC->SR.bit.CSTS) {\n }\n CMCC->MAINT0.bit.INVALL = 1;\n CMCC->CTRL.bit.CEN = 1;\n#endif\n}\n\nint ZFlash::totalSize() {\n return (8 << NVMCTRL->PARAM.bit.PSZ) * NVMCTRL->PARAM.bit.NVMP;\n}\n\n// this returns the size of \"page\" that can be erased (\"row\" in datasheet)\nint ZFlash::pageSize(uintptr_t address) {\n#ifdef SAMD51\n if (address < (uintptr_t)totalSize())\n return NVMCTRL_BLOCK_SIZE; // 8k\n#else\n if (address < (uintptr_t)totalSize())\n return 256;\n#endif\n target_panic(DEVICE_FLASH_ERROR);\n return 0;\n}\n\n#ifdef SAMD51\n#define CMD(D21, D51) NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | D51\n#else\n#define CMD(D21, D51) NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | D21\n#endif\n\nint ZFlash::erasePage(uintptr_t address) {\n LOG(\"Erase %x\", address);\n#ifdef SAMD51\n NVMCTRL->CTRLA.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN_Val;\n#else\n NVMCTRL->CTRLB.bit.MANW = 1;\n#endif\n waitForLast();\n unlock();\n#ifdef SAMD51\n NVMCTRL->ADDR.reg = address;\n#else\n // yeah... /2\n NVMCTRL->ADDR.reg = address / 2;\n#endif\n CMD(NVMCTRL_CTRLA_CMD_ER, NVMCTRL_CTRLB_CMD_EB);\n waitForLast();\n lock();\n return 0;\n}\n\n#if 0\n#define CHECK_ECC() \\\n if (NVMCTRL->INTFLAG.bit.ECCSE || NVMCTRL->INTFLAG.bit.ECCDE) \\\n return -10\n#else\n#define CHECK_ECC() ((void)0)\n#endif\n\nint ZFlash::writeBytes(uintptr_t dst, const void *src, uint32_t len) {\n#ifdef SAMD51\n CHECK_ECC();\n\n // only allow writing double word at a time\n if (len & 7)\n return -1;\n if (dst & 7)\n return -2;\n\n // every double-word can only be written once, otherwise we get ECC errors\n // and no, ECC cannot be disabled\n for (unsigned i = 0; i < (len >> 3); ++i)\n if (((uint64_t *)dst)[i] != 0xffffffffffffffff &&\n ((uint64_t *)src)[i] != 0xffffffffffffffff)\n return -3;\n#define WRITE_SIZE 16\n#else\n if ((dst & 3) || (len & 3))\n return -1;\n\n for (unsigned i = 0; i < len; ++i)\n if (((uint8_t *)dst)[i] != 0xff && ((uint8_t *)src)[i] != 0xff)\n return -3;\n#define WRITE_SIZE 64\n#endif\n\n uint32_t writeBuf[WRITE_SIZE >> 2];\n uint32_t idx = 0;\n\n waitForLast();\n unlock();\n __DMB();\n\n while (idx < len) {\n uint32_t off = dst & (WRITE_SIZE - 1);\n uint32_t n = WRITE_SIZE - off;\n if (n > len - idx)\n n = len - idx;\n uint32_t *sp;\n volatile uint32_t *dp;\n if (n != WRITE_SIZE) {\n memset(writeBuf, 0xff, WRITE_SIZE);\n memcpy((uint8_t *)writeBuf + off, src, n);\n sp = writeBuf;\n dp = (uint32_t *)(dst - off);\n } else {\n sp = (uint32_t *)src;\n dp = (uint32_t *)dst;\n }\n\n bool need = false;\n for (unsigned i = 0; i < (WRITE_SIZE >> 2); ++i)\n if (sp[i] != 0xffffffff) {\n need = true;\n break;\n }\n\n if (need) {\n CMD(NVMCTRL_CTRLA_CMD_PBC, NVMCTRL_CTRLB_CMD_PBC);\n waitForLast();\n\n uint32_t q = WRITE_SIZE >> 2;\n\n target_disable_irq();\n while (q--) {\n auto v = *sp++;\n *dp = v;\n dp++;\n }\n\n CMD(NVMCTRL_CTRLA_CMD_WP, NVMCTRL_CTRLB_CMD_WQW);\n target_enable_irq();\n waitForLast();\n }\n\n src = (uint8_t *)src + n;\n dst += n;\n idx += n;\n }\n\n CHECK_ECC();\n\n lock();\n\n return 0;\n}\n} // namespace codal\n#endif\n",
2183
2183
  "STM32Flash.cpp": "#include \"pxt.h\"\n#include \"Flash.h\"\n\n//#define LOG DMESG\n#define LOG NOLOG\n\n#ifdef STM32F4\nnamespace codal {\nstatic void waitForLast() {\n while ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY)\n ;\n}\n\nstatic void unlock() {\n FLASH->CR |= FLASH_CR_LOCK;\n FLASH->KEYR = FLASH_KEY1;\n FLASH->KEYR = FLASH_KEY2;\n}\n\nstatic void lock() {\n FLASH->CR |= FLASH_CR_LOCK;\n}\n\nint ZFlash::pageSize(uintptr_t address) {\n address |= 0x08000000;\n if (address < 0x08010000)\n return 16 * 1024;\n if (address < 0x08020000)\n return 64 * 1024;\n if (address < 0x08100000)\n return 128 * 1024;\n target_panic(DEVICE_FLASH_ERROR);\n return 0;\n}\n\nint ZFlash::totalSize() {\n return *((uint16_t *)0x1FFF7A22) * 1024;\n}\n\nint ZFlash::erasePage(uintptr_t address) {\n waitForLast();\n unlock();\n\n address |= 0x08000000;\n uintptr_t ptr = 0x08000000;\n int sectNum = 0;\n while (1) {\n ptr += pageSize(ptr);\n if (ptr > address)\n break;\n sectNum++;\n }\n\n FLASH->CR = FLASH_CR_PSIZE_1 | (sectNum << FLASH_CR_SNB_Pos) | FLASH_CR_SER;\n FLASH->CR |= FLASH_CR_STRT;\n\n waitForLast();\n\n FLASH->CR = FLASH_CR_PSIZE_1;\n lock();\n\n // cache flushing only required after erase, not programming (3.5.4)\n __HAL_FLASH_DATA_CACHE_DISABLE();\n __HAL_FLASH_DATA_CACHE_RESET();\n __HAL_FLASH_DATA_CACHE_ENABLE();\n\n // we skip instruction cache, as we're not expecting to erase that\n\n return 0;\n}\n\nint ZFlash::writeBytes(uintptr_t dst, const void *src, uint32_t len) {\n LOG(\"WR flash at %p len=%d\", (void *)dst, len);\n\n if ((dst & 3) || ((uintptr_t)src & 3) || (len & 3))\n return -1;\n\n for (unsigned i = 0; i < len; ++i)\n if (((uint8_t *)dst)[i] != 0xff && ((uint8_t *)src)[i] != 0xff)\n return -3;\n\n waitForLast();\n unlock();\n\n dst |= 0x08000000;\n\n FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;\n\n volatile uint32_t *sp = (uint32_t *)src;\n volatile uint32_t *dp = (uint32_t *)dst;\n len >>= 2;\n\n while (len-- > 0) {\n uint32_t v = *sp++;\n if (v != 0xffffffff) {\n *dp++ = v;\n waitForLast();\n } else {\n dp++;\n }\n }\n\n FLASH->CR = FLASH_CR_PSIZE_1;\n lock();\n\n LOG(\"WR flash OK\");\n\n return 0;\n}\n} // namespace codal\n#endif\n",
2184
- "pxt.json": "{\n \"name\": \"settings\",\n \"description\": \"Settings storage in internal flash\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"RAFFS.cpp\",\n \"RAFFS.h\",\n \"Flash.h\",\n \"STM32Flash.cpp\",\n \"SAMDFlash.cpp\",\n \"NRF52Flash.cpp\",\n \"RP2040Flash.cpp\",\n \"settings.cpp\",\n \"settings.ts\",\n \"shims.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2184
+ "pxt.json": "{\n \"name\": \"settings\",\n \"description\": \"Settings storage in internal flash\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"RAFFS.cpp\",\n \"RAFFS.h\",\n \"Flash.h\",\n \"STM32Flash.cpp\",\n \"SAMDFlash.cpp\",\n \"NRF52Flash.cpp\",\n \"RP2040Flash.cpp\",\n \"settings.cpp\",\n \"settings.ts\",\n \"shims.d.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2185
2185
  "settings.cpp": "\n#include \"pxt.h\"\n#include \"RAFFS.h\"\n#include \"GhostFAT.h\"\n\nusing namespace pxt::raffs;\nusing namespace codal;\n\nnamespace settings {\n\n#if defined(SAMD21)\n#define SETTINGS_SIZE (2 * 1024)\n#else\n#define SETTINGS_SIZE (32 * 1024)\n#endif\n\nclass WStorage {\n public:\n CODAL_FLASH flash;\n FS fs;\n bool isMounted;\n\n WStorage()\n : flash(),\n#if defined(STM32F4)\n fs(flash, 0x8008000, SETTINGS_SIZE),\n#elif defined(SAMD51)\n fs(flash, 512 * 1024 - SETTINGS_SIZE, SETTINGS_SIZE),\n#elif defined(SAMD21)\n fs(flash, 256 * 1024 - SETTINGS_SIZE, SETTINGS_SIZE),\n#elif defined(NRF52_SERIES)\n#define NRF_BOOTLOADER_START *(uint32_t *)0x10001014\n fs(flash,\n 128 * 1024 < NRF_BOOTLOADER_START && NRF_BOOTLOADER_START < (uint32_t)flash.totalSize()\n ? NRF_BOOTLOADER_START - SETTINGS_SIZE\n : flash.totalSize() - SETTINGS_SIZE,\n SETTINGS_SIZE),\n#elif defined(PICO_BOARD)\n // XIP bias 0x10000000\n fs(flash, 0x10000000 + flash.totalSize() - SETTINGS_SIZE - 4096, SETTINGS_SIZE),\n#else\n fs(flash),\n#endif\n isMounted(false) {\n fs.minGCSpacing = 10000;\n }\n};\nSINGLETON(WStorage);\n\nstatic WStorage *mountedStorage() {\n auto s = getWStorage();\n if (s->fs.tryMount())\n return s;\n s->fs.exists(\"foobar\"); // forces mount and possibly format\n return s;\n}\n\n// large store is area for storing large binary objects, eg ML models\n// it may be already occupied by the user program, in which case largeStoreStart() will return 0\nsize_t largeStoreSize() {\n#if defined(SAMD21)\n return 64 * 1024;\n#else\n return 128 * 1024;\n#endif\n}\n\nuintptr_t largeStoreStart() {\n auto s = getWStorage();\n uintptr_t r;\n#if defined(STM32F4)\n r = 0x08000000 + s->flash.totalSize() - largeStoreSize();\n#else\n r = s->fs.baseAddr - s->fs.bytes - largeStoreSize();\n#endif\n\n if (r < afterProgramPage())\n return 0;\n\n return r;\n}\n\nCODAL_FLASH *largeStoreFlash() {\n return &getWStorage()->flash;\n}\n\n//%\nint _set(String key, Buffer data) {\n auto s = mountedStorage();\n return s->fs.write(key->getUTF8Data(), data->data, data->length);\n}\n\n//%\nint _remove(String key) {\n auto s = mountedStorage();\n return s->fs.remove(key->getUTF8Data());\n}\n\n//%\nbool _exists(String key) {\n auto s = mountedStorage();\n return s->fs.exists(key->getUTF8Data());\n}\n\n//%\nBuffer _get(String key) {\n auto s = mountedStorage();\n auto sz = s->fs.read(key->getUTF8Data(), NULL, 0);\n if (sz < 0)\n return NULL;\n auto ret = mkBuffer(NULL, sz);\n registerGCObj(ret);\n s->fs.read(NULL, ret->data, ret->length);\n unregisterGCObj(ret);\n return ret;\n}\n\nstatic bool isSystem(const char *fn) {\n return fn[0] == '#';\n}\n\n//%\nvoid _userClean() {\n auto s = mountedStorage();\n DMESG(\"clearing user files\");\n s->fs.forceGC(isSystem);\n // if system files take more than 25% of storage size, we reformat\n // it likely means user code has written some 'system' files\n if (s->fs.freeSize() < 3 * s->fs.totalSize() / 4) {\n s->fs.format();\n }\n}\n\n//%\nRefCollection *_list(String prefix) {\n auto st = mountedStorage();\n st->fs.dirRewind();\n auto res = Array_::mk();\n registerGCObj(res);\n\n auto prefData = prefix->getUTF8Data();\n auto prefLen = prefix->getUTF8Size();\n auto wantsInternal = prefData[0] == '#';\n\n for (;;) {\n auto d = st->fs.dirRead();\n if (!d)\n break;\n if (!wantsInternal && d->name[0] == '#')\n continue;\n if (memcmp(d->name, prefData, prefLen) != 0)\n continue;\n auto str = mkString(d->name, -1);\n registerGCObj(str);\n res->head.push((TValue)str);\n unregisterGCObj(str);\n }\n unregisterGCObj(res);\n return res;\n}\n\n} // namespace settings\n",
2186
2186
  "settings.ts": "namespace settings {\n const RUN_KEY = \"#run\";\n const SCOPE_KEY = \"#scope\";\n const DEVICE_SECRETS_KEY = \"#secrets\";\n const SECRETS_KEY = \"__secrets\";\n\n //% shim=pxt::seedAddRandom\n declare function seedAddRandom(n: number): void;\n\n //% shim=settings::_set\n declare function _set(key: string, data: Buffer): int32;\n\n //% shim=settings::_remove\n declare function _remove(key: string): int32;\n\n //% shim=settings::_exists\n declare function _exists(key: string): boolean;\n\n //% shim=settings::_get\n declare function _get(key: string): Buffer;\n\n //% shim=settings::_userClean\n declare function _userClean(): void;\n\n //% shim=settings::_list\n declare function _list(prefix: string): string[];\n\n export function runNumber() {\n return readNumber(RUN_KEY) || 0\n }\n\n function setScope(scope: string) {\n if (!scope || scope.length > 100)\n control.panic(922)\n const currScope = readString(SCOPE_KEY)\n if (currScope != scope) {\n _userClean()\n writeString(SCOPE_KEY, scope)\n }\n }\n\n function initScopes() {\n const rn = runNumber() + 1\n writeNumber(RUN_KEY, rn)\n\n seedAddRandom(control.deviceSerialNumber() & 0x7fffffff)\n seedAddRandom(rn)\n\n setScope(control.programName())\n }\n\n initScopes()\n\n /** \n * Delete all non-system settings.\n */\n export function clear(): void {\n _userClean()\n }\n\n /**\n * Set named setting to a given buffer.\n */\n export function writeBuffer(key: string, value: Buffer) {\n if (_set(key, value)) {\n // if we're out of space, clear user storage\n _userClean()\n // and panic - reset should hopefully recreate needed files\n control.panic(920)\n }\n }\n\n /**\n * Set named settings to a given string.\n */\n export function writeString(key: string, value: string) {\n writeBuffer(key, control.createBufferFromUTF8(value))\n }\n\n /**\n * Set named settings to a given JSON object.\n */\n export function writeJSON(key: string, value: any) {\n writeString(key, JSON.stringify(value))\n }\n\n /**\n * Set named settings to a given number.\n */\n export function writeNumber(key: string, value: number) {\n writeBuffer(key, msgpack.packNumberArray([value]))\n }\n\n /**\n * Set named settings to a given array of numbers.\n */\n export function writeNumberArray(key: string, value: number[]) {\n writeBuffer(key, msgpack.packNumberArray(value))\n }\n\n /**\n * Read named setting as a buffer. Returns undefined when setting not found.\n */\n export function readBuffer(key: string) {\n return _get(key)\n }\n\n /**\n * Read named setting as a string.\n */\n export function readString(key: string) {\n const buf = readBuffer(key)\n if (!buf)\n return undefined\n else\n return buf.toString()\n }\n\n /**\n * Read named setting as a JSON object.\n */\n export function readJSON(key: string) {\n const s = readString(key)\n if (s)\n return JSON.parse(s)\n return undefined\n }\n\n /**\n * Read named setting as a number.\n */\n export function readNumber(key: string) {\n const buf = readBuffer(key)\n if (!buf)\n return undefined\n else {\n const nums = msgpack.unpackNumberArray(buf)\n if (nums && nums.length >= 1)\n return nums[0]\n return undefined\n }\n }\n\n /**\n * Read named setting as a number.\n */\n export function readNumberArray(key: string) {\n const buf = readBuffer(key)\n if (!buf)\n return undefined\n else\n return msgpack.unpackNumberArray(buf)\n }\n\n /**\n * Return a list of settings starting with a given prefix.\n */\n export function list(prefix?: string) {\n if (!prefix) prefix = \"\"\n return _list(prefix)\n }\n\n /**\n * Remove named setting.\n */\n export function remove(key: string) {\n _remove(key)\n }\n\n /**\n * Check if a named setting exists.\n */\n export function exists(key: string) {\n return _exists(key)\n }\n\n function clone(v: any): any {\n if (v == null) return null\n return JSON.parse(JSON.stringify(v))\n }\n\n function isKV(v: any) {\n return !!v && typeof v === \"object\" && !Array.isArray(v)\n }\n\n function jsonMergeFrom(trg: any, src: any) {\n if (!src) return;\n const keys = Object.keys(src)\n keys.forEach(k => {\n const srck = src[k];\n if (isKV(trg[k]) && isKV(srck))\n jsonMergeFrom(trg[k], srck);\n else\n trg[k] = clone(srck);\n });\n }\n\n //% fixedInstances\n export class SecretStore {\n constructor(private key: string) { }\n\n setSecret(name: string, value: any) {\n const secrets = this.readSecrets();\n secrets[name] = value;\n writeJSON(this.key, secrets);\n }\n\n updateSecret(name: string, value: any) {\n const secrets = this.readSecrets();\n const secret = secrets[name];\n if (secret === undefined)\n secrets[name] = value;\n else jsonMergeFrom(secret, value);\n writeJSON(this.key, secrets)\n }\n\n readSecret(name: string, ensure: boolean = false): any {\n const secrets = this.readSecrets();\n const secret = secrets[name];\n if (ensure && !secret)\n throw \"missing secret \" + name;\n return secret;\n }\n\n clearSecrets() {\n writeString(this.key, \"{}\");\n }\n\n readSecrets(): any {\n try {\n return readJSON(this.key) || {}\n } catch {\n control.dmesg(\"invalid secret format\")\n return {};\n }\n }\n }\n\n /**\n * Secrets shared by any program on the device\n */\n //% fixedInstance whenUsed block=\"device secrets\"\n export const deviceSecrets = new SecretStore(DEVICE_SECRETS_KEY);\n\n /**\n * Program secrets\n */\n //% fixedInstance whenUsed block=\"program secrets\"\n export const programSecrets = new SecretStore(SECRETS_KEY);\n}\n",
2187
2187
  "shims.d.ts": "\n"
2188
2188
  },
2189
2189
  "settings---files": {
2190
- "pxt.json": "{\n \"name\": \"settings---files\",\n \"description\": \"Settings storage in files\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"settings.cpp\",\n \"settings.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2190
+ "pxt.json": "{\n \"name\": \"settings---files\",\n \"description\": \"Settings storage in files\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"settings.cpp\",\n \"settings.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n }\n}\n",
2191
2191
  "settings.cpp": "#define _GNU_SOURCE 1\n\n#include \"pxt.h\"\n\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <dirent.h>\n#include <errno.h>\n\n#define FAIL(msg) \\\n do { \\\n DMESG(\"FAILURE: %s\", msg); \\\n abort(); \\\n } while (0)\n\nnamespace settings {\n\n#define ADD(c) \\\n do { \\\n buf[dp] = (c); \\\n dp++; \\\n if (dp > 1000) \\\n FAIL(\"too long\"); \\\n } while (0)\n\nconst char *hexD = \"0123456789abcdef\";\n\nstatic char *encodeString(const char *str) {\n static char buf[1024];\n int dp = 0;\n for (auto sp = str; *sp; ++sp) {\n auto c = *sp;\n if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z'))\n ADD(c);\n else if (('A' <= c && c <= 'Z')) {\n ADD('-');\n ADD(c | 0x20);\n } else {\n ADD('_');\n ADD(hexD[(c >> 4) & 0xf]);\n ADD(hexD[c & 0xf]);\n }\n }\n\n ADD(0);\n\n return buf;\n}\n\nstatic int hex(char c) {\n if ('0' <= c && c <= '9')\n return c - '0';\n c |= 0x20;\n if ('a' <= c && c <= 'f')\n return c - 'a' + 10;\n return -1;\n}\n\nstatic char *decodeString(const char *str) {\n static char buf[1024];\n int dp = 0;\n\n if (strlen(str) > 1000)\n FAIL(\"too long decode\");\n\n for (auto sp = str; *sp; ++sp) {\n auto c = *sp;\n if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z'))\n ADD(c);\n else if (c == '-' && sp[1]) {\n ADD(sp[1] & ~0x20);\n sp++;\n } else if (c == '_' && hex(sp[1]) >= 0 && hex(sp[2]) >= 0) {\n ADD((hex(sp[1]) << 4) | hex(sp[2]));\n sp += 2;\n }\n }\n\n ADD(0);\n\n return buf;\n}\n\nstatic const char *settingsDirectory() {\n static char *name;\n if (name)\n return name;\n#ifdef SETTINGSDIR\n asprintf(&name, \"%s/%s\", SETTINGSDIR, encodeString(programName()->getUTF8Data()));\n#else\n asprintf(&name, \"%s.data\", initialArgv[0]);\n#endif\n#ifdef __WIN32__\n mkdir(name);\n#else\n mkdir(name, 0777);\n#endif\n return name;\n}\n\nstatic const char *keyName(const char *key) {\n static char *lastName;\n if (lastName)\n free(lastName);\n auto dirname = settingsDirectory();\n asprintf(&lastName, \"%s/%s\", dirname, encodeString(key));\n return lastName;\n}\n\nstatic const char *keyName(String key) {\n return keyName(key->getUTF8Data());\n}\n\nstatic FILE *openKey(String key, const char *mode) {\n return fopen(keyName(key), mode);\n}\n\n//%\nint _set(String key, Buffer data) {\n // DMESG(\"set[%s] - %p\", key->getUTF8Data(), data);\n auto f = openKey(key, \"wb\");\n if (!f) {\n DMESG(\"errno=%d\", errno);\n FAIL(\"can't write file\");\n }\n fwrite(data->data, data->length, 1, f);\n fclose(f);\n return 0;\n}\n\n//%\nint _remove(String key) {\n return remove(keyName(key));\n}\n\n//%\nbool _exists(String key) {\n auto f = openKey(key, \"rb\");\n if (f != NULL)\n fclose(f);\n return f != NULL;\n}\n\n//%\nBuffer _get(String key) {\n auto f = openKey(key, \"rb\");\n if (f == NULL)\n return NULL;\n fseek(f, 0, SEEK_END);\n auto sz = ftell(f);\n auto ret = mkBuffer(NULL, sz);\n registerGCObj(ret);\n fseek(f, 0, SEEK_SET);\n fread(ret->data, ret->length, 1, f);\n fclose(f);\n unregisterGCObj(ret);\n return ret;\n}\n\n//%\nvoid _userClean() {\n auto dp = opendir(settingsDirectory());\n if (!dp)\n return;\n for (;;) {\n dirent *ep = readdir(dp);\n if (!ep)\n break;\n auto name = decodeString(ep->d_name);\n if (name[0] == '#')\n continue;\n remove(keyName(name));\n }\n closedir(dp);\n}\n\n//%\nRefCollection *_list(String prefix) {\n auto res = Array_::mk();\n registerGCObj(res);\n\n auto prefData = prefix->getUTF8Data();\n auto prefLen = prefix->getUTF8Size();\n auto wantsInternal = prefData[0] == '#';\n\n auto dp = opendir(settingsDirectory());\n\n for (;;) {\n dirent *ep = dp ? readdir(dp) : NULL;\n if (!ep)\n break;\n auto name = decodeString(ep->d_name);\n if (!wantsInternal && name[0] == '#')\n continue;\n if (memcmp(name, prefData, prefLen) != 0)\n continue;\n auto str = mkString(name, -1);\n registerGCObj(str);\n res->head.push((TValue)str);\n unregisterGCObj(str);\n }\n if (dp)\n closedir(dp);\n unregisterGCObj(res);\n\n return res;\n}\n\n} // namespace settings\n",
2192
2192
  "settings.ts": "namespace settings {\n const RUN_KEY = \"#run\";\n const SCOPE_KEY = \"#scope\";\n const DEVICE_SECRETS_KEY = \"#secrets\";\n const SECRETS_KEY = \"__secrets\";\n\n //% shim=pxt::seedAddRandom\n declare function seedAddRandom(n: number): void;\n\n //% shim=settings::_set\n declare function _set(key: string, data: Buffer): int32;\n\n //% shim=settings::_remove\n declare function _remove(key: string): int32;\n\n //% shim=settings::_exists\n declare function _exists(key: string): boolean;\n\n //% shim=settings::_get\n declare function _get(key: string): Buffer;\n\n //% shim=settings::_userClean\n declare function _userClean(): void;\n\n //% shim=settings::_list\n declare function _list(prefix: string): string[];\n\n export function runNumber() {\n return readNumber(RUN_KEY) || 0\n }\n\n function setScope(scope: string) {\n if (!scope || scope.length > 100)\n control.panic(922)\n const currScope = readString(SCOPE_KEY)\n if (currScope != scope) {\n _userClean()\n writeString(SCOPE_KEY, scope)\n }\n }\n\n function initScopes() {\n const rn = runNumber() + 1\n writeNumber(RUN_KEY, rn)\n\n seedAddRandom(control.deviceSerialNumber() & 0x7fffffff)\n seedAddRandom(rn)\n\n setScope(control.programName())\n }\n\n initScopes()\n\n /** \n * Delete all non-system settings.\n */\n export function clear(): void {\n _userClean()\n }\n\n /**\n * Set named setting to a given buffer.\n */\n export function writeBuffer(key: string, value: Buffer) {\n if (_set(key, value)) {\n // if we're out of space, clear user storage\n _userClean()\n // and panic - reset should hopefully recreate needed files\n control.panic(920)\n }\n }\n\n /**\n * Set named settings to a given string.\n */\n export function writeString(key: string, value: string) {\n writeBuffer(key, control.createBufferFromUTF8(value))\n }\n\n /**\n * Set named settings to a given JSON object.\n */\n export function writeJSON(key: string, value: any) {\n writeString(key, JSON.stringify(value))\n }\n\n /**\n * Set named settings to a given number.\n */\n export function writeNumber(key: string, value: number) {\n writeBuffer(key, msgpack.packNumberArray([value]))\n }\n\n /**\n * Set named settings to a given array of numbers.\n */\n export function writeNumberArray(key: string, value: number[]) {\n writeBuffer(key, msgpack.packNumberArray(value))\n }\n\n /**\n * Read named setting as a buffer. Returns undefined when setting not found.\n */\n export function readBuffer(key: string) {\n return _get(key)\n }\n\n /**\n * Read named setting as a string.\n */\n export function readString(key: string) {\n const buf = readBuffer(key)\n if (!buf)\n return undefined\n else\n return buf.toString()\n }\n\n /**\n * Read named setting as a JSON object.\n */\n export function readJSON(key: string) {\n const s = readString(key)\n if (s)\n return JSON.parse(s)\n return undefined\n }\n\n /**\n * Read named setting as a number.\n */\n export function readNumber(key: string) {\n const buf = readBuffer(key)\n if (!buf)\n return undefined\n else {\n const nums = msgpack.unpackNumberArray(buf)\n if (nums && nums.length >= 1)\n return nums[0]\n return undefined\n }\n }\n\n /**\n * Read named setting as a number.\n */\n export function readNumberArray(key: string) {\n const buf = readBuffer(key)\n if (!buf)\n return undefined\n else\n return msgpack.unpackNumberArray(buf)\n }\n\n /**\n * Return a list of settings starting with a given prefix.\n */\n export function list(prefix?: string) {\n if (!prefix) prefix = \"\"\n return _list(prefix)\n }\n\n /**\n * Remove named setting.\n */\n export function remove(key: string) {\n _remove(key)\n }\n\n /**\n * Check if a named setting exists.\n */\n export function exists(key: string) {\n return _exists(key)\n }\n\n function clone(v: any): any {\n if (v == null) return null\n return JSON.parse(JSON.stringify(v))\n }\n\n function isKV(v: any) {\n return !!v && typeof v === \"object\" && !Array.isArray(v)\n }\n\n function jsonMergeFrom(trg: any, src: any) {\n if (!src) return;\n const keys = Object.keys(src)\n keys.forEach(k => {\n const srck = src[k];\n if (isKV(trg[k]) && isKV(srck))\n jsonMergeFrom(trg[k], srck);\n else\n trg[k] = clone(srck);\n });\n }\n\n //% fixedInstances\n export class SecretStore {\n constructor(private key: string) { }\n\n setSecret(name: string, value: any) {\n const secrets = this.readSecrets();\n secrets[name] = value;\n writeJSON(this.key, secrets);\n }\n\n updateSecret(name: string, value: any) {\n const secrets = this.readSecrets();\n const secret = secrets[name];\n if (secret === undefined)\n secrets[name] = value;\n else jsonMergeFrom(secret, value);\n writeJSON(this.key, secrets)\n }\n\n readSecret(name: string, ensure: boolean = false): any {\n const secrets = this.readSecrets();\n const secret = secrets[name];\n if (ensure && !secret)\n throw \"missing secret \" + name;\n return secret;\n }\n\n clearSecrets() {\n writeString(this.key, \"{}\");\n }\n\n readSecrets(): any {\n try {\n return readJSON(this.key) || {}\n } catch {\n control.dmesg(\"invalid secret format\")\n return {};\n }\n }\n }\n\n /**\n * Secrets shared by any program on the device\n */\n //% fixedInstance whenUsed block=\"device secrets\"\n export const deviceSecrets = new SecretStore(DEVICE_SECRETS_KEY);\n\n /**\n * Program secrets\n */\n //% fixedInstance whenUsed block=\"program secrets\"\n export const programSecrets = new SecretStore(SECRETS_KEY);\n}\n"
2193
2193
  },
2194
2194
  "sevenseg": {
2195
2195
  "README.md": "# Seven segment\n\nFunctions and classes to create a seven segment display.\n",
2196
- "pxt.json": "{\n \"name\": \"sevenseg\",\n \"description\": \"Seven segment digit display\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"sevenseg.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/sevenseg.png\"\n}\n",
2196
+ "pxt.json": "{\n \"name\": \"sevenseg\",\n \"description\": \"Seven segment digit display\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"sevenseg.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"icon\": \"/static/libs/sevenseg.png\"\n}\n",
2197
2197
  "sevenseg.ts": "enum SegmentStyle {\n //% block=\"blank\"\n Blank = 0,\n //% block=\"thin\"\n Thin = 1,\n //% block=\"narrow\"\n Narrow = 2,\n //% block=\"medium\"\n Medium = 3,\n //% block=\"thick\"\n Thick = 4\n}\n\nenum DigitRadix {\n //% block=\"decimal\"\n Decimal = 10,\n //% block=\"hex\"\n Hex = 16,\n //% block=\"octal\"\n Octal = 8,\n //% block=\"alpha\"\n Alpha = 26\n}\n\nenum SegmentScale {\n //% block=\"full\"\n Full,\n //% block=\"half\"\n Half\n}\n\n// \"0123456789ABCDEFHJLoPrUY-°\"\nenum SegmentCharacter {\n //% block=\"0\"\n ZERO,\n //% block=\"1\"\n ONE,\n //% block=\"2\"\n TWO,\n //% block=\"3\"\n THREE,\n //% block=\"4\"\n FOUR,\n //% block=\"5\"\n FIVE,\n //% block=\"6\"\n SIX,\n //% block=\"7\"\n SEVEN,\n //% block=\"8\"\n EIGHT,\n //% block=\"9\"\n NINE,\n //% block=\"A\"\n A,\n //% block=\"B\"\n B,\n //% block=\"C\"\n C,\n //% block=\"D\"\n D,\n //% block=\"E\"\n E,\n //% block=\"F\"\n F,\n //% block=\"H\"\n H,\n //% block=\"J\"\n J,\n //% block=\"L\"\n L,\n //% block=\"o\"\n o,\n //% block=\"P\"\n P,\n //% block=\"r\"\n r,\n //% block=\"U\"\n U,\n //% block=\"Y\"\n Y,\n //% block=\"-\"\n Hyphen,\n //% block=\"°\"\n Degree\n}\n\n/**\n* Seven segment display digits and gizmos\n*/\n//% icon=\"\\uf2a1\" color=\"#4682B4\" blockGap=8\n//% groups='[\"Create\", \"Counter\", \"Digits\"]'\nnamespace sevenseg {\n\n // Copy these array sets along with the array mapping string into Node to get the\n // formatting of the segment buffer data.\n\n /*\n var fullSegment: number[][] = [\n [1, 0, 14, 0, 2, 1, 13, 1, 3, 2, 12, 2, 4, 3, 11, 3],\n [15, 2, 15, 14, 14, 3, 14, 13, 13, 4, 13, 12, 12, 5, 12, 11],\n [15, 17, 15, 29, 14, 18, 14, 28, 13, 19, 13, 27, 12, 20, 12, 26],\n [1, 31, 14, 31, 2, 30, 13, 30, 3, 29, 12, 29, 4, 28, 11, 28],\n [0, 17, 0, 29, 1, 18, 1, 28, 2, 19, 2, 27, 3, 20, 3, 26],\n [0, 2, 0, 14, 1, 3, 1, 13, 2, 4, 2, 12, 3, 5, 3, 11],\n [2, 15, 13, 15, 2, 16, 13, 16, 3, 14, 12, 14, 3, 17, 12, 17]\n ];\n \"hex`\" + fullSegment.map(n => n.toString(16)).map(n => n.length < 2 ? \"0\" + n : n).join(\"\") + \"`\"\n */\n\n // packed metrics of pixel drawing for full size digit segments\n const fullSegment: Buffer[] = [\n hex`01000e0002010d0103020c0204030b03`,\n hex`0f020f0e0e030e0d0d040d0c0c050c0b`,\n hex`0f110f1d0e120e1c0d130d1b0c140c1a`,\n hex`011f0e1f021e0d1e031d0c1d041c0b1c`,\n hex`0011001d0112011c0213021b0314031a`,\n hex`0002000e0103010d0204020c0305030b`,\n hex`020f0d0f02100d10030e0c0e03110c11`\n ];\n\n /*\n var halfSegment: number[][] = [\n [1, 0, 6, 0, 2, 1, 5, 1],\n [7, 2, 7, 6, 6, 3, 6, 5],\n [7, 8, 7, 13, 6, 9, 6, 12],\n [1, 15, 6, 15, 2, 14, 5, 14],\n [0, 8, 0, 13, 1, 9, 1, 12],\n [0, 2, 0, 6, 1, 3, 1, 5],\n [2, 7, 5, 7, 2, 7, 5, 7]\n ];\n \"hex`\" + halfSegment.map(n => n.toString(16)).map(n => n.length < 2 ? \"0\" + n : n).join(\"\") + \"`\"\n */\n\n // packed metrics of pixel drawing for half size digit segments\n const halfSegment: Buffer[] = [\n hex`0100060002010501`,\n hex`0702070606030605`,\n hex`0708070d0609060c`,\n hex`010f060f020e050e`,\n hex`0008000d0109010c`,\n hex`0002000601030105`,\n hex`0207050702070507`\n ];\n\n // Seven segment layout and id assignments\n //\n // a\n // =========\n // || ||\n // f || || b\n // || g ||\n // =========\n // || ||\n // e || || c\n // || d ||\n // =========\n\n /*\n const segmapIds = [\"abcdef\", \"bc\", \"abdeg\", \"abcdg\", \"bcfg\", \"acdfg\", \"acdefg\", \"abc\", \"abcdefg\", \"abcdfg\"];\n var segmap = [\n 0b11111100, // '0' digit maps \"abcdef..\"\n 0b01100000, // '1' digit maps \".bc.....\"\n 0b11011010, // '2' digit maps \"ab.de.g.\"\n 0b11110010, // '3' digit maps \"abcd..g.\"\n 0b01100110, // '4' digit maps \".bc..fg.\"\n 0b10110110, // '5' digit maps \"a.cd.fg.\"\n 0b10111110, // '6' digit maps \"a.cdefg.\"\n 0b11100000, // '7' digit maps \"abc.....\"\n 0b11111110, // '8' digit maps \"abcdefg.\"\n 0b11110110, // '9' digit maps \"abcd.fg.\"\n 0b11101110, // 'A' digit maps \"abc.efg.\"\n 0b00111110, // 'b' digit maps \"..cdefg.\"\n 0b10011100, // 'C' digit maps \"a..def..\"\n 0b01111010, // 'd' digit maps \".bcde.g.\"\n 0b10011110, // 'E' digit maps \"a..defg.\"\n 0b10001110, // 'F' digit maps \"a...efg.\"\n 0b01101110, // 'H' digit maps \".bc.efg.\"\n 0b01111000, // 'J' digit maps \".bcde...\"\n 0b00011100, // 'L' digit maps \"...def..\"\n 0b00111010, // 'o' digit maps \"..cde.g.\"\n 0b11001110, // 'P' digit maps \"ab..efg.\"\n 0b00001010, // 'r' digit maps \"....e.g.\"\n 0b01111100, // 'U' digit maps \".bcdef..\"\n 0b01110110, // 'Y' digit maps \".bcd.fg.\"\n 0b00000010, // '-' digit maps \"......g.\"\n 0b11000110 // '°' digit maps \"ab...fg.\"\n ];\n \"hex`\" + segmap.map(n => n.toString(16)).map(n => n.length < 2 ? \"0\" + n : n).join(\"\") + \"`\"\n */\n \n const segmap: Buffer = hex`fc60daf266b6bee0fef6ee3e9c7a9e8e6e781c3ace0a7c7602c6`;\n\n export function drawSegment(digit: Image, segment: Buffer, thickness: SegmentStyle, color: number) {\n let offset = 0;\n let x, y, w, h = 0;\n if (segment.length >= thickness * 4) {\n for (let i = 0; i < thickness; i++) {\n x = segment.getNumber(NumberFormat.Int8LE, offset + 0);\n y = segment.getNumber(NumberFormat.Int8LE, offset + 1);\n w = segment.getNumber(NumberFormat.Int8LE, offset + 2) - x + 1;\n h = segment.getNumber(NumberFormat.Int8LE, offset + 3) - y + 1;\n digit.fillRect(x, y, w, h, color);\n offset += 4;\n }\n }\n }\n \n export function drawDigit(digit: Image, value: number, thickness: SegmentStyle, scale: SegmentScale, color: number) {\n let segment: Buffer = null;\n let digitMap = segmap.getNumber(NumberFormat.Int8LE, value)\n\n digit.fill(0);\n for (let i = 0; digitMap != 0; i++) {\n if ((digitMap & 0x80) != 0) {\n segment = scale == SegmentScale.Full ? fullSegment[i] : halfSegment[i];\n if (scale == SegmentScale.Half && thickness > SegmentStyle.Narrow) {\n thickness = SegmentStyle.Narrow;\n }\n drawSegment(digit, segment, thickness, color)\n }\n digitMap = digitMap << 1;\n }\n }\n \n /**\n * Create a seven segment display digit\n * @param thickness the width of the segments, eg: SegmentStyle.Thick\n * @param value optional initial display value, eg: 0\n */\n //% group=\"Create\"\n //% blockId=sevenseg_create block=\"seven segment digit || of %thickness with value %value\"\n //% expandableArgumentMode=toggle\n //% blockSetVariable=myDigit\n //% value.min=0 value.max=9 value.defl=0\n //% weight=99\n //% help=sevenseg/create-digit\n export function createDigit(thickness: SegmentStyle = SegmentStyle.Thick, value: number = 0): SevenSegDigit {\n return new SevenSegDigit(thickness, value)\n }\n\n /**\n * Create a seven segment counter display\n * @param thickness the width of the segments, eg: SegmentStyle.Thick\n * @param scale the size of the segments, eg: SegmentScale.Full\n * @param numDigits the number of digits displayed, eg: 1\n */\n //% group=\"Create\"\n //% blockId=sevenseg_createcounter block=\"counter || of %thickness segments at %scale size with %numDigits digits\"\n //% expandableArgumentMode=toggle\n //% blockSetVariable=myCounter\n //% numDigits.min=1 numDigits.max=5 numDigits.defl=1\n //% weight=100\n //% help=sevenseg/create-counter\n export function createCounter(thickness: SegmentStyle = SegmentStyle.Thick, scale: SegmentScale = SegmentScale.Full, numDigits: number = 1): DigitCounter {\n return new DigitCounter(thickness, scale, numDigits)\n }\n}\n\n//% blockNamespace=sevenseg color=\"#4682B4\" blockGap=8\nclass SevenSegDigit {\n private digit: Image;\n private digitSprite: Sprite;\n private _value: number;\n private thickness: SegmentStyle;\n private color: number;\n private scale: SegmentScale;\n private _x: number;\n private _y: number;\n private _radix: number;\n \n constructor(thickness: SegmentStyle = SegmentStyle.Thick, value: number = 0) {\n this._value = value;\n this.digit = image.create(16, 32);\n this.digitSprite = sprites.create(this.digit, 0);\n this._x = this.digitSprite.x\n this._y = this.digitSprite.y\n this.thickness = thickness;\n this.color = 2;\n this.scale = SegmentScale.Full;\n this._radix = DigitRadix.Decimal;\n sevenseg.drawDigit(this.digit, this.value, thickness, this.scale, this.color);\n }\n\n /**\n * Set the display value to a digit character: '0'- '9'\n * @param alphaChar the display value, eg: \"0\"\n */\n //% group=\"Digits\"\n //% blockId=sevenseg_setalpha block=\"set %sevenseg(myDigit) display value to %alphaChar\"\n //% weight=40\n setDigitAlpha(alphaChar: SegmentCharacter) {\n const matchChars = \"0123456789ABCDEFHJLoPrUY-°\";\n if (alphaChar == this.value || alphaChar < 0 || alphaChar >= matchChars.length)\n return;\n this._value = alphaChar;\n sevenseg.drawDigit(this.digit, this.value, this.thickness, this.scale, this.color);\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"value\" weight=90\n get value(): number {\n return this._value;\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"value\" weight=90\n set value(value: number) {\n value = value | 0;\n if (value != this.value) {\n if (value >= 0 && value < this._radix) {\n this._value = value;\n } else {\n this._value = value % this._radix;\n }\n sevenseg.drawDigit(this.digit, this._value, this.thickness, this.scale, this.color);\n }\n }\n\n /**\n * Set the display digit color\n * @param color of the digit display, eg: 2\n */\n //% group=\"Digits\"\n //% blockId=sevenseg_setcolor block=\"set %sevenseg(myDigit) display color to %color=colorindexpicker\"\n //% weight=35\n //% help=sevenseg/sevensegdigit/set-digit-color\n setDigitColor(color: number): void {\n this.color = color;\n sevenseg.drawDigit(this.digit, this.value, this.thickness, this.scale, this.color);\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"x\"\n get x(): number {\n return this.digitSprite.x;\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"x\"\n set x(v: number) {\n this._x = v;\n this.digitSprite.x = v;\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"y\"\n get y(): number {\n return this.digitSprite.y;\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"y\"\n set y(v: number) {\n this._y = v;\n this.digitSprite.y = v;\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"width\"\n get width(): number {\n return this.digitSprite.width;\n }\n\n //% group=\"Digits\" blockSetVariable=\"myDigit\"\n //% blockCombine block=\"height\"\n get height(): number {\n return this.digitSprite.height;\n }\n\n /**\n * Set the display radix of the digit\n * @param radix of the digit display, eg: DigitRadix.Decimal\n */\n //% blockId=sevenseg_setradix block=\"set display radix of %sevenseg(myDigit) to %radix\"\n //% group=\"Digits\" weight=30\n //% help=sevenseg/sevensegdigit/set-radix\n setRadix(radix: DigitRadix) {\n this._radix = radix;\n sevenseg.drawDigit(this.digit, this.value, this.thickness, this.scale, this.color);\n }\n\n /**\n * Set the display digit size\n * @param scale of the digit display, eg: SegmentScale.Full\n */\n //% group=\"Digits\"\n //% blockId=sevenseg_setdigitscale block=\"set %sevenseg(myDigit) to %scale size\"\n //% weight=25 \n //% help=sevenseg/sevensegdigit/set-scale\n setScale(scale: SegmentScale): void {\n if (scale != this.scale) {\n this.scale = scale;\n if (scale == SegmentScale.Full) {\n this.digit = image.create(16, 32)\n } else {\n this.digit = image.create(8, 16)\n }\n this.digitSprite.setImage(this.digit);\n this.digitSprite.x = this._x;\n this.digitSprite.y = this._y;\n sevenseg.drawDigit(this.digit, this.value, this.thickness,this.scale, this.color);\n }\n }\n}\n\n//% blockNamespace=sevenseg color=\"#4682B4\" blockGap=8\nclass DigitCounter {\n private _count: number;\n private limit: number\n private _x: number;\n private _y: number;\n private numDigits: number;\n private maxDigits: number\n private digits: SevenSegDigit[];\n private thickness: SegmentStyle;\n private color: number;\n private scale: SegmentScale;\n\n constructor(thickness: SegmentStyle = SegmentStyle.Thick, scale: SegmentScale = SegmentScale.Full, numDigits: number = 3) {\n this._count = 0;\n this.maxDigits = 5;\n this.color = 2\n this.scale = scale;\n numDigits = Math.clamp(1, this.maxDigits, numDigits);\n\n this.thickness = thickness;\n this.digits = [];\n this.digits.push(new SevenSegDigit(this.thickness, 0));\n this.digits[0].setScale(this.scale);\n this.digits[0].setDigitColor(this.color);\n this.numDigits = 1;\n this.limit = 10;\n this._x = this.digits[0].x;\n this._y = this.digits[0].y;\n\n for (let i = 1; i < numDigits; i++) {\n this.addDigit();\n }\n }\n\n /**\n * Add a digit to the counter\n */\n addDigit() {\n let newDigit: SevenSegDigit = null\n if (this.numDigits < this.maxDigits) {\n newDigit = new SevenSegDigit(this.thickness, 0);\n newDigit.setScale(this.scale)\n newDigit.setDigitColor(this.color)\n this.digits.push(newDigit);\n this.numDigits += 1;\n this.limit = this.limit * 10;\n this.adjustDigitPositions();\n }\n }\n\n //% group=\"Counter\" blockSetVariable=\"myCounter\"\n //% blockCombine block=\"count\"\n get count() {\n return this._count;\n }\n\n //% group=\"Counter\" blockSetVariable=\"myCounter\"\n //% blockCombine block=\"count\"\n set count(value: number) {\n if (value >= 0 && value < this.limit) {\n this._count = value;\n this.updateDisplayValue()\n }\n }\n\n private updateDisplayValue()\n {\n let decimator = 1;\n let updateValue = 0;\n for (let i = 0; i < this.digits.length; i++) {\n updateValue = this._count / decimator % 10;\n this.digits[i].value = updateValue;\n decimator = decimator * 10;\n }\n }\n\n private adjustDigitPositions() {\n let spacing = this.digits[0].width * 4 / 3;\n let offset = this.digits[0].x + spacing / 2;\n for (let i = 0; i < this.numDigits; i++) {\n this.digits[i].x = offset;\n offset -= spacing;\n }\n }\n\n private moveDigits() {\n let spacing = this.digits[0].width * 4 / 3;\n for (let i = 1; i < this.numDigits; i++) {\n this.digits[i].x = this.digits[i - 1].x - spacing;\n this.digits[i].y = this.digits[0].y;\n }\n this._x = (this.digits[0].x + this.digits[this.numDigits - 1].x) / 2;\n this._y = this.digits[0].y;\n }\n \n /**\n * Set the counter display digit color\n * @param color of the digit display, eg: 2\n */\n //% group=\"Counter\"\n //% blockId=sevenseg_setcountercolor block=\"set %sevenseg(myCounter) display color to %color=colorindexpicker\"\n //% weight=86\n //% help=sevenseg/digitcounter/set-digit-color\n setDigitColor(color: number): void {\n this.color = color;\n for (let i = 0; i < this.numDigits; i++) {\n this.digits[i].setDigitColor(color);\n }\n }\n\n //% group=\"Counter\" blockSetVariable=\"myCounter\"\n //% blockCombine block=\"x\"\n get x(): number {\n return this._x;\n }\n\n //% group=\"Counter\" blockSetVariable=\"myCounter\"\n //% blockCombine block=\"x\"\n set x(v: number) {\n this.digits[0].x += v - this._x;\n this.moveDigits()\n }\n\n //% group=\"Counter\" blockSetVariable=\"myCounter\"\n //% blockCombine block=\"y\"\n get y(): number {\n return this._y;\n }\n\n //% group=\"Counter\" blockSetVariable=\"myCounter\"\n //% blockCombine block=\"y\"\n set y(v: number) {\n this.digits[0].y = v;\n this.moveDigits()\n }\n}\n"
2198
2198
  },
2199
2199
  "sprite-scaling": {
2200
2200
  "README.md": "# Sprite Scaling\n\nAdditional sprite scaling methods.\n",
2201
- "pxt.json": "{\n \"name\": \"sprite-scaling\",\n \"description\": \"Additional scaling blocks for sprites\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"scaling.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 80,\n \"icon\": \"/static/libs/sprite-scaling.png\"\n}\n",
2201
+ "pxt.json": "{\n \"name\": \"sprite-scaling\",\n \"description\": \"Additional scaling blocks for sprites\",\n \"dependencies\": {\n \"game\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"scaling.ts\",\n \"targetoverrides.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"weight\": 80,\n \"icon\": \"/static/libs/sprite-scaling.png\"\n}\n",
2202
2202
  "scaling.ts": "//% color=\"#95078E\" weight=99 icon=\"\\uf338\"\nnamespace scaling {\n //% blockId=sprite_scale_to_percent_ex\n //% block=\"set $sprite=variables_get(mySprite) scale to $value percent $direction anchor $anchor\"\n //% expandableArgumentMode=enabled\n //% inlineInputMode=inline\n //% value.defl=150\n //% direction.defl=ScaleDirection.Uniformly\n //% anchor.defl=ScaleAnchor.Middle\n //% help=sprites/scaling/scale-to-percent\n export function scaleToPercent(sprite: Sprite, value: number, direction?: ScaleDirection, anchor?: ScaleAnchor): void {\n value /= 100;\n direction = direction || ScaleDirection.Uniformly;\n anchor = anchor || ScaleAnchor.Middle;\n\n let sx: number;\n let sy: number;\n\n if (direction & ScaleDirection.Horizontally) sx = value;\n if (direction & ScaleDirection.Vertically) sy = value;\n\n sprite.setScaleCore(sx, sy, anchor);\n }\n\n //% blockId=sprite_scale_by_percent_ex\n //% block=\"change $sprite=variables_get(mySprite) scale by $value percent $direction anchor $anchor\"\n //% expandableArgumentMode=enabled\n //% inlineInputMode=inline\n //% value.defl=50\n //% direction.defl=ScaleDirection.Uniformly\n //% anchor.defl=ScaleAnchor.Middle\n //% help=sprites/scaling/scale-by-percent\n export function scaleByPercent(sprite: Sprite, value: number, direction?: ScaleDirection, anchor?: ScaleAnchor): void {\n value /= 100;\n direction = direction || ScaleDirection.Uniformly;\n anchor = anchor || ScaleAnchor.Middle;\n\n let sx: number;\n let sy: number;\n\n if (direction & ScaleDirection.Horizontally) sx = sprite.sx + value;\n if (direction & ScaleDirection.Vertically) sy = sprite.sy + value;\n\n sprite.setScaleCore(sx, sy, anchor);\n }\n\n //% blockId=sprite_scale_to_pixels_ex\n //% block=\"set $sprite=variables_get(mySprite) scale to $value pixels $direction anchor $anchor || proportional $proportional\"\n //% expandableArgumentMode=enabled\n //% inlineInputMode=inline\n //% value.defl=32\n //% direction.defl=ScaleDirection.Horizontally\n //% anchor.defl=ScaleAnchor.Middle\n //% proportional.defl=0\n //% help=sprites/scaling/scale-to-pixels\n export function scaleToPixels(sprite: Sprite, value: number, direction?: ScaleDirection, anchor?: ScaleAnchor, proportional?: boolean): void {\n direction = direction || ScaleDirection.Horizontally;\n anchor = anchor || ScaleAnchor.Middle;\n\n if (proportional == null) proportional = direction === ScaleDirection.Uniformly;\n\n let sx: number;\n let sy: number;\n\n if (direction & ScaleDirection.Horizontally) {\n const imgW = sprite.image.width;\n const newW = value;\n sx = newW / imgW;\n }\n\n if (direction & ScaleDirection.Vertically) {\n const imgH = sprite.image.height;\n const newH = value;\n sy = newH / imgH;\n }\n\n sprite.setScaleCore(sx, sy, anchor, proportional);\n }\n\n //% blockId=sprite_scale_by_pixels_ex\n //% block=\"change $sprite=variables_get(mySprite) scale by $value pixels $direction anchor $anchor || proportional $proportional\"\n //% expandableArgumentMode=enabled\n //% inlineInputMode=inline\n //% value.defl=10\n //% direction.defl=ScaleDirection.Horizontally\n //% anchor.defl=ScaleAnchor.Middle\n //% proportional.defl=0\n //% help=sprites/scaling/scale-by-pixels\n export function scaleByPixels(sprite: Sprite, value: number, direction?: ScaleDirection, anchor?: ScaleAnchor, proportional?: boolean): void {\n direction = direction || ScaleDirection.Horizontally;\n anchor = anchor || ScaleAnchor.Middle;\n\n if (proportional == null) proportional = direction === ScaleDirection.Uniformly;\n\n let sx: number;\n let sy: number;\n\n if (direction & ScaleDirection.Horizontally) {\n const imgW = sprite.image.width;\n const newW = sprite.width + value;\n sx = newW / imgW;\n }\n\n if (direction & ScaleDirection.Vertically) {\n const imgH = sprite.image.height;\n const newH = sprite.height + value;\n sy = newH / imgH;\n }\n\n sprite.setScaleCore(sx, sy, anchor, proportional);\n }\n}",
2203
2203
  "targetoverrides.ts": "// TODO any platform specific overrides",
2204
2204
  "test.ts": ""
@@ -2206,7 +2206,7 @@ var pxtTargetBundle = {
2206
2206
  "storyboard": {
2207
2207
  "README.md": "# Storyboard\n\nOrchestrate scenes",
2208
2208
  "loader.ts": "namespace storyboard {\n function loader(done: () => void) {\n const font = image.font8;\n let m = 40;\n let w = screen.width - 2 * m;\n let c = 2;\n let y = screen.height / 2 - c;\n let x = 0;\n game.onPaint(function() {\n screen.printCenter(\"MakeCode Arcade\", y - font.charHeight - c, 1, font);\n screen.drawRect(m, y, w, 2 * c, 1)\n screen.fillRect(m, y + 1, x, 2 * c - 2, 3);\n\n x++;\n if (x == w) done();\n })\n }\n\n /**\n * Default boot sequence\n */\n //% block=\"loader\" fixedInstance whenUsed\n export const loaderBootSequence = new BootSequence(loader, 0);\n}",
2209
- "pxt.json": "{\n \"name\": \"storyboard\",\n \"description\": \"Scene manager\",\n \"dependencies\": {\n \"game\": \"*\",\n \"color\": \"*\",\n \"palette\": \"*\"\n },\n \"files\": [\n \"storyboard.ts\",\n \"loader.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"weight\": 81,\n \"icon\": \"/static/libs/storyboard.png\"\n}\n",
2209
+ "pxt.json": "{\n \"name\": \"storyboard\",\n \"description\": \"Scene manager\",\n \"dependencies\": {\n \"game\": \"*\",\n \"color\": \"*\",\n \"palette\": \"*\"\n },\n \"files\": [\n \"storyboard.ts\",\n \"loader.ts\",\n \"README.md\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"searchOnly\": true,\n \"weight\": 81,\n \"icon\": \"/static/libs/storyboard.png\"\n}\n",
2210
2210
  "storyboard.ts": "/**\n * A manager of scenes\n */\n//% icon=\"\\uf009\"\n//% weight=87 color=\"#401255\"\nnamespace storyboard {\n export interface FrameOptions {\n background?: number;\n }\n\n export class Frame {\n start: () => void;\n options: FrameOptions;\n\n constructor(start: () => void, options: FrameOptions) {\n this.start = start;\n this.options = options || {};\n }\n }\n\n //% fixedInstances\n export class BootSequence {\n start: (done: () => void) => void;\n background: number;\n constructor(start: (done: () => void) => void, background: number) {\n this.start = start;\n this.background = background;\n }\n\n /**\n * Registers the boot sequence\n */\n //% block=\"storyboard register %boot| boot sequence\" blockId=storyboardregister\n register() {\n registerBootSequence(this);\n }\n }\n\n let _boots: BootSequence[];\n let _scenes: {\n [index: string]: Frame\n };\n let _nav: Frame[];\n\n function registerBootSequence(boot: BootSequence) {\n if (!_boots)\n _boots = [];\n if (_boots.indexOf(boot) < 0)\n _boots.push(boot);\n }\n\n /**\n * Registers a scene\n * @param name \n * @param scene \n */\n export function registerScene(name: string, start: () => void, options?: FrameOptions) {\n if (!name) return;\n if (!_scenes) {\n _scenes = {};\n }\n _scenes[name] = new Frame(start, options);\n }\n\n function fadeBackground(last: BootSequence, next: BootSequence) {\n if (last.background == next.background) return;\n\n const fadeLength = palette.defaultPalette().length;\n const fadeGradient = color.gradient(\n last.background,\n next.background,\n fadeLength\n );\n\n palette.setColors(fadeGradient);\n for (let i = 0; i < fadeLength; i++) {\n scene.setBackgroundColor(i);\n pause(50);\n }\n scene.setBackgroundColor(0xf);\n palette.reset();\n }\n\n function consumeBootSequence() {\n // run boot sequences if any\n let boot: BootSequence;\n let previous: BootSequence;\n while (boot = _boots && _boots.shift()) {\n game.pushScene();\n if (previous)\n fadeBackground(previous, boot);\n let isDone = false;\n boot.start(() => isDone = true);\n pauseUntil(() => isDone);\n game.popScene();\n previous = boot;\n }\n }\n\n /**\n * Starts the story board by running boot sequences then entering a scene\n * @param name \n */\n //% block=\"storyboard start at $name\" blockId=storyboardstart\n export function start(name?: string) {\n consumeBootSequence();\n // grab the first frame\n push(name || (_scenes && Object.keys(_scenes)[0]));\n }\n\n function isActive(name: string): boolean {\n const scene = name && _scenes && _scenes[name];\n return scene && (_nav && _nav.length && _nav[_nav.length - 1] == scene);\n }\n\n /**\n * Replace the current scene with the given scene\n * @param name \n */\n //% block=\"storyboard replace scene $name\" blockId=storyboardreplace\n export function replace(name: string) {\n if (isActive(name)) return;\n\n const scene = name && _scenes && _scenes[name];\n if (!scene) return; // not found\n\n if (!_nav) _nav = [];\n if (_nav.length) {\n _nav.pop();\n game.popScene();\n }\n _nav.push(scene);\n game.pushScene();\n scene.start();\n }\n\n /**\n * Transition to a registered scene\n * @param name \n */\n //% block=\"storyboard push scene $name\" blockId=storyboardpush\n export function push(name: string) {\n if (isActive(name)) return;\n\n const scene = name && _scenes && _scenes[name];\n if (!scene) return; // not found\n\n if (!_nav) _nav = [];\n if (_nav.length) {\n game.popScene();\n }\n _nav.push(scene);\n game.pushScene();\n scene.start();\n }\n\n /**\n * Stops the current scene and restart the previous scene\n */\n //% block=\"storyboard pop frame\" blockId=storyboardpop\n export function pop() {\n const n = _nav && _nav.pop();\n if (n) {\n game.popScene();\n }\n // restart previous\n if (_nav && _nav.length) {\n const sc = _nav[_nav.length - 1];\n game.pushScene();\n sc.start();\n }\n }\n}",
2211
2211
  "test.ts": "let mySprite = sprites.create(img`\n . . . . . . b b b b a a . . . .\n . . . . b b d d d 3 3 3 a a . .\n . . . b d d d 3 3 3 3 3 3 a a .\n . . b d d 3 3 3 3 3 3 3 3 3 a .\n . b 3 d 3 3 3 3 3 b 3 3 3 3 a b\n . b 3 3 3 3 3 a a 3 3 3 3 3 a b\n b 3 3 3 3 3 a a 3 3 3 3 d a 4 b\n b 3 3 3 3 b a 3 3 3 3 3 d a 4 b\n b 3 3 3 3 3 3 3 3 3 3 d a 4 4 e\n a 3 3 3 3 3 3 3 3 3 d a 4 4 4 e\n a 3 3 3 3 3 3 3 d d a 4 4 4 e .\n a a 3 3 3 d d d a a 4 4 4 e e .\n . e a a a a a a 4 4 4 4 e e . .\n . . e e b b 4 4 4 4 b e e . . .\n . . . e e e e e e e e . . . . .\n . . . . . . . . . . . . . . . .\n`, SpriteKind.Player)\nmySprite.x = 10\ncontroller.moveSprite(mySprite)\nstoryboard.loaderBootSequence.register()\nstoryboard.registerScene(\"lemon\", function () {\n let mySprite2 = sprites.create(img`\n 4 4 4 . . 4 4 4 4 4 . . . . . .\n 4 5 5 4 4 5 5 5 5 5 4 4 . . . .\n b 4 5 5 1 5 1 1 1 5 5 5 4 . . .\n . b 5 5 5 5 1 1 5 5 1 1 5 4 . .\n . b d 5 5 5 5 5 5 5 5 1 1 5 4 .\n b 4 5 5 5 5 5 5 5 5 5 5 1 5 4 .\n c d 5 5 5 5 5 5 5 5 5 5 5 5 5 4\n c d 4 5 5 5 5 5 5 5 5 5 5 1 5 4\n c 4 5 5 5 d 5 5 5 5 5 5 5 5 5 4\n c 4 d 5 4 5 d 5 5 5 5 5 5 5 5 4\n . c 4 5 5 5 5 d d d 5 5 5 5 5 b\n . c 4 d 5 4 5 d 4 4 d 5 5 5 4 c\n . . c 4 4 d 4 4 4 4 4 d d 5 d c\n . . . c 4 4 4 4 4 4 4 4 5 5 5 4\n . . . . c c b 4 4 4 b b 4 5 4 4\n . . . . . . c c c c c c b b 4 .\n `, SpriteKind.Player)\n mySprite2.y = 20\n controller.moveSprite(mySprite2)\n controller.A.onEvent(ControllerButtonEvent.Pressed, function () {\n storyboard.push(\"burger\");\n })\n controller.B.onEvent(ControllerButtonEvent.Pressed, function () {\n storyboard.pop();\n })\n})\nstoryboard.registerScene(\"burger\", function () {\n let mySprite3 = sprites.create(img`\n . . . . c c c b b b b b . . . .\n . . c c b 4 4 4 4 4 4 b b b . .\n . c c 4 4 4 4 4 5 4 4 4 4 b c .\n . e 4 4 4 4 4 4 4 4 4 5 4 4 e .\n e b 4 5 4 4 5 4 4 4 4 4 4 4 b c\n e b 4 4 4 4 4 4 4 4 4 4 5 4 4 e\n e b b 4 4 4 4 4 4 4 4 4 4 4 b e\n . e b 4 4 4 4 4 5 4 4 4 4 b e .\n 8 7 e e b 4 4 4 4 4 4 b e e 6 8\n 8 7 2 e e e e e e e e e e 2 7 8\n e 6 6 2 2 2 2 2 2 2 2 2 2 6 c e\n e c 6 7 6 6 7 7 7 6 6 7 6 c c e\n e b e 8 8 c c 8 8 c c c 8 e b e\n e e b e c c e e e e e c e b e e\n . e e b b 4 4 4 4 4 4 4 4 e e .\n . . . c c c c c e e e e e . . .\n `, SpriteKind.Player)\n mySprite3.y = 80\n controller.moveSprite(mySprite3)\n controller.A.onEvent(ControllerButtonEvent.Pressed, function () {\n storyboard.replace(\"lemon\");\n })\n controller.B.onEvent(ControllerButtonEvent.Pressed, function () {\n storyboard.pop()\n })\n})\ncontroller.A.onEvent(ControllerButtonEvent.Pressed, function () {\n storyboard.start(\"lemon\")\n})\ncontroller.B.onEvent(ControllerButtonEvent.Pressed, function () {\n storyboard.start(\"burger\")\n})\n\n"
2212
2212
  },
@@ -2217,13 +2217,13 @@ var pxtTargetBundle = {
2217
2217
  "assets/js/custom.js": "/**\n * This will be loaded before starting the simulator.\n * If you wish to add custom javascript, \n * ** make sure to add this line to pxt.json**\n * \n * \"disableTargetTemplateFiles\": true\n * \n * otherwise MakeCode will override your changes.\n * \n * To register a constrol simmessages, use addSimMessageHandler\n */\n",
2218
2218
  "assets/js/loader.js": "var channelHandlers = {}\n\nfunction addSimMessageHandler(channel, handler) {\n channelHandlers[channel] = handler;\n}\n\nfunction makeCodeRun(options) {\n var code = \"\";\n var isReady = false;\n var simState = {}\n var simStateChanged = false\n var started = false;\n var meta = undefined;\n\n // hide scrollbar\n window.scrollTo(0, 1);\n // init runtime\n initSimState();\n fetchCode();\n\n // helpers\n function fetchCode() {\n sendReq(options.js, function (c, status) {\n if (status != 200)\n return;\n code = c;\n // find metadata\n code.replace(/^\\/\\/\\s+meta=([^\\n]+)\\n/m, function (m, metasrc) {\n meta = JSON.parse(metasrc);\n })\n var vel = document.getElementById(\"version\");\n if (meta.version && meta.repo && vel) {\n var ap = document.createElement(\"a\");\n ap.download = \"arcade.uf2\";\n ap.href = \"https://github.com/\" + meta.repo + \"/releases/download/v\" + meta.version + \"/arcade.uf2\";\n ap.innerText = \"v\" + meta.version;\n vel.appendChild(ap);\n }\n // load simulator with correct version\n document.getElementById(\"simframe\")\n .setAttribute(\"src\", meta.simUrl);\n initFullScreen();\n })\n }\n\n function startSim() {\n if (!code || !isReady || started)\n return\n setState(\"run\");\n started = true;\n const runMsg = {\n type: \"run\",\n parts: [],\n code: code,\n partDefinitions: {},\n cdnUrl: meta.cdnUrl,\n version: meta.target,\n storedState: simState,\n frameCounter: 1,\n options: {\n \"theme\": \"green\",\n \"player\": \"\"\n },\n id: \"green-\" + Math.random()\n }\n postMessage(runMsg);\n }\n\n function stopSim() {\n setState(\"stopped\");\n postMessage({\n type: \"stop\"\n });\n started = false;\n }\n\n window.addEventListener('message', function (ev) {\n var d = ev.data\n if (d.type == \"ready\") {\n var loader = document.getElementById(\"loader\");\n if (loader)\n loader.remove();\n isReady = true;\n startSim();\n } else if (d.type == \"simulator\") {\n switch (d.command) {\n case \"restart\":\n stopSim();\n startSim();\n break;\n case \"setstate\":\n if (d.stateValue === null)\n delete simState[d.stateKey];\n else\n simState[d.stateKey] = d.stateValue;\n simStateChanged = true;\n break;\n }\n } else if (d.type === \"messagepacket\" && d.channel) {\n const handler = channelHandlers[d.channel]\n if (handler) {\n try {\n const buf = d.data;\n const str = uint8ArrayToString(buf);\n const data = JSON.parse(str)\n handler(data);\n } catch (e) {\n console.log(`invalid simmessage`)\n console.log(e)\n }\n }\n } \n }, false);\n\n // helpers\n function uint8ArrayToString(input) {\n let len = input.length;\n let res = \"\"\n for (let i = 0; i < len; ++i)\n res += String.fromCharCode(input[i]);\n return res;\n } \n\n function setState(st) {\n var r = document.getElementById(\"root\");\n if (r)\n r.setAttribute(\"data-state\", st);\n }\n\n function postMessage(msg) {\n const frame = document.getElementById(\"simframe\");\n if (frame)\n frame.contentWindow.postMessage(msg, meta.simUrl);\n }\n\n function sendReq(url, cb) {\n var xhttp = new XMLHttpRequest();\n xhttp.onreadystatechange = function () {\n if (xhttp.readyState == 4) {\n cb(xhttp.responseText, xhttp.status)\n }\n };\n xhttp.open(\"GET\", url, true);\n xhttp.send();\n }\n\n function initSimState() {\n try {\n simState = JSON.parse(localStorage[\"simstate\"])\n } catch (e) {\n simState = {}\n }\n setInterval(function () {\n if (simStateChanged)\n localStorage[\"simstate\"] = JSON.stringify(simState)\n simStateChanged = false\n }, 200)\n }\n \n function initFullScreen() {\n var sim = document.getElementById(\"simframe\");\n var fs = document.getElementById(\"fullscreen\");\n if (fs && sim.requestFullscreen) {\n fs.onclick = function() { sim.requestFullscreen(); }\n } else if (fs) {\n fs.remove();\n }\n }\n}",
2219
2219
  "index.html": "---\n# this is an empty front matter\n---\n<!DOCTYPE html>\n<html>\n\n<head>\n <meta charset=\"utf-8\">\n <title>{{ site.github.project_title }}</title>\n <meta name=\"description\" content=\"{{ site.github.project_tagline }}\" />\n <meta name=\"author\" content=\"{{ site.github.owner_name }}\">\n <meta name=\"twitter:card\" content=\"summary\" />\n <meta name=\"twitter:site\" content=\"/\" />\n <meta name=\"twitter:title\" content=\"{{ site.github.project_tagline }}\" />\n <meta name=\"twitter:description\" content=\"{{ site.github.project_tagline }}\" />\n <meta name=\"twitter:image\" content=\"./icon.png\" />\n <meta name=\"mobile-web-app-capable\" content=\"yes\">\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n <meta name=\"apple-mobile-web-app-title\" content=\"{{ site.github.project_title }}\">\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"translucent-black\">\n <meta name=\"format-detection\" content=\"telephone=no\">\n <meta name=\"application-name\" content=\"{{ site.github.project_title }}\">\n <meta name=\"theme-color\" content=\"#000\">\n <meta property=\"og:title\" content=\"{{ site.github.project_title }}\" />\n <meta property=\"og:site_name\" content=\"{{ site.github.project_title }}\" />\n <meta property=\"og:description\" content=\"{{ site.github.project_tagline }}\" />\n <meta property=\"og:image\" content=\"./icon.png\" />\n <link rel=\"apple-touch-icon\" href=\"./icon.png\">\n <link rel=\"icon\" type=\"image/png\" href=\"./icon.png\">\n <link rel=\"shortcut icon\" href=\"./icon.png\">\n <script type=\"text/javascript\" src=\"./assets/js/loader.js?v={{ site.github.build_revision }}\"></script>\n <script type=\"text/javascript\" src=\"./assets/js/custom.js?v={{ site.github.build_revision }}\"></script>\n <style>\n body {\n background: black;\n color: white;\n font-family: monospace;\n overflow: hidden;\n font-size: 14pt;\n }\n\n .embed {\n background: transparent;\n }\n\n iframe {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: calc(100% - 1.5em);\n border: none;\n }\n\n .nofooter iframe {\n height: 100%;\n }\n\n footer {\n color: grey;\n position: absolute;\n bottom: 0;\n width: 100%;\n left: 0;\n z-index: 100;\n text-align: center;\n font-size: 1em;\n margin-bottom: 0.25em;\n }\n\n footer a {\n color: grey;\n }\n\n .embed footer,\n .embed footer a {\n color: black;\n }\n\n #fullscreen {\n position: absolute;\n right: 0.25rem;\n bottom: 0;\n cursor: pointer;\n }\n .lds-ripple {\n width: 80px;\n height: 80px;\n margin: auto;\n position: absolute;\n margin: auto;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: -1;\n }\n\n .lds-ripple div {\n position: absolute;\n border: 4px solid #fff;\n opacity: 1;\n border-radius: 50%;\n animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;\n }\n\n .lds-ripple div:nth-child(2) {\n animation-delay: -0.5s;\n }\n\n @keyframes lds-ripple {\n 0% {\n top: 36px;\n left: 36px;\n width: 0;\n height: 0;\n opacity: 1;\n }\n\n 100% {\n top: 0px;\n left: 0px;\n width: 72px;\n height: 72px;\n opacity: 0;\n }\n }\n </style>\n</head>\n\n<body id=\"root\">\n <div id=\"loader\" class=\"lds-ripple\">\n <div></div>\n <div></div>\n <svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" x=\"0\" y=\"0\" viewBox=\"0 0 32 32\" xml:space=\"preserve\"\n id=\"svg2\">\n <style type=\"text/css\" id=\"style4\"></style>\n <g id=\"g4212\" transform=\"matrix(.79626 0 0 .79626 -68.322 9.868)\">\n <path\n d=\"M105.989-5.487v.01a1.91 1.91 0 00-1.613 1.83c0 .779.417 1.119.417 1.15.413.435.238.913-.589.874 0 0-3.009.015-3.066 0a.724.724 0 00-.53.696v9.894c-.001.39.314.705.705.705h9.848c.39 0 .705-.314.705-.705V5.475c-.126-.423-.489-.463-.827-.141-.032 0-.369.417-1.147.417-.93-.03-1.69-.72-1.83-1.616h-.013a6.771 6.771 0 010-.494h.012c.142-.897.9-1.587 1.83-1.616.78 0 1.116.417 1.148.417.329.313.695.238.827-.138V-.927a.72.72 0 00-.527-.696c-.057.015-3.07 0-3.07 0-.74.06-.998-.44-.585-.874 0-.031.417-.371.417-1.15-.029-.93-.72-1.69-1.616-1.83v-.01a6.241 6.241 0 00-.496 0z\"\n id=\"path167\" fill=\"#fff\" fill-opacity=\"1\" stroke-width=\"1.57\" />\n <path\n d=\"M98.633-7.18c-.917 0-1.624.252-2.158.774-.534.521-.802 1.208-.822 2.094a552.379 552.379 0 01-.062 2.732c-.02.776-.081 1.354-.187 1.766-.118.46-.331.853-.637 1.168-.272.28-.684.587-1.254.938-.255.156-.368.387-.368.748 0 .351.077.481.11.521.12.145.32.3.592.463.376.226.702.494.972.795.3.334.518.786.662 1.38.052.213.112.882.172 4.228.006.566.138 1.07.39 1.502.25.431.584.753 1.02.984.443.235.971.356 1.57.356.974 0 1.055-.377 1.055-.764 0-.266-.054-.465-.157-.591a.501.501 0 00-.334-.2c-.374-.042-.66-.103-.87-.187a1.29 1.29 0 01-.678-.622c-.127-.244-.206-.588-.242-1.049a22.82 22.82 0 01-.046-1.68c0-.707-.034-1.327-.099-1.846a4.868 4.868 0 00-.31-1.26 2.848 2.848 0 00-.52-.843 4.267 4.267 0 00-.874-.702l-.773-.485.773-.487c.502-.318.88-.657 1.128-1.012.244-.35.413-.783.503-1.282.099-.55.153-1.333.169-2.333 0-.713.014-1.247.042-1.625.032-.437.105-.774.221-1.027.147-.317.382-.548.68-.672.214-.086.506-.152.896-.205a.429.429 0 00.224-.089.622.622 0 00.178-.251 1.11 1.11 0 00.089-.451c0-.268-.07-.45-.215-.57-.175-.144-.456-.215-.84-.215z\"\n id=\"path165\" fill=\"#fff\" fill-opacity=\"1\" stroke-width=\"1.57\" />\n <path\n d=\"M113.887-7.182c-.974 0-1.055.377-1.055.763 0 .267.05.467.153.592.1.12.205.182.338.2.374.042.658.103.867.186.294.116.524.326.678.623.127.245.206.588.242 1.048.032.397.046.945.046 1.68 0 .708.034 1.328.098 1.846.06.49.166.917.31 1.264.138.332.313.616.521.843.22.239.511.473.871.699l.773.487-.77.488c-.502.317-.882.656-1.128 1.009-.244.35-.414.78-.503 1.278-.099.551-.154 1.338-.169 2.337 0 .712-.015 1.246-.043 1.625-.03.437-.1.77-.217 1.024a1.294 1.294 0 01-.68.674c-.214.087-.506.154-.896.206a.44.44 0 00-.227.089.64.64 0 00-.178.251c-.06.135-.086.282-.086.45 0 .268.066.45.212.571.174.144.458.218.843.218.917 0 1.62-.254 2.155-.776.534-.522.802-1.205.822-2.091.023-1.095.046-2.007.064-2.735.02-.777.079-1.355.184-1.766.12-.46.333-.854.638-1.168.273-.28.684-.587 1.254-.938.254-.157.368-.385.368-.746 0-.35-.077-.483-.11-.524-.119-.143-.316-.298-.589-.463a4.268 4.268 0 01-.975-.794c-.3-.334-.515-.784-.66-1.377-.051-.213-.114-.885-.174-4.23-.007-.568-.138-1.072-.39-1.503a2.524 2.524 0 00-1.02-.984c-.443-.235-.968-.356-1.567-.356z\"\n id=\"path163\" fill=\"#fff\" fill-opacity=\"1\" stroke-width=\"1.57\" />\n </g>\n <path\n d=\"M28.621 31.422c.224-.102.208 1.099.208-15.49 0-16.588.016-15.388-.208-15.49-.144-.065-24.6-.065-24.744 0-.223.102-.207-1.1-.206 15.498.001 12.58.01 15.259.052 15.334.112.203-.702.19 12.515.192 9.446.001 12.307-.01 12.383-.044zm-9.415-1.705c-.283-.11-.57-.4-.678-.687a1.216 1.216 0 011.131-1.655c.669 0 1.213.544 1.213 1.213 0 .853-.862 1.437-1.666 1.129zm-8.337-1.054v-.757H9.353v-1.668h1.516V24.723H12.536V26.238h1.516v1.668h-1.516V29.42H10.869zm10.99-1.22c-.284-.109-.57-.399-.678-.686a1.204 1.204 0 01.276-1.298c.762-.762 2.067-.222 2.067.855 0 .854-.862 1.438-1.666 1.13zM4.765 23.475l-.111-.11V1.377l.11-.111.111-.11h22.746l.11.11.112.11V23.366l-.111.11-.11.111H4.875z\"\n id=\"path4210\" fill=\"#fff\" fill-opacity=\"1\" />\n </svg>\n </div>\n <iframe id=\"simframe\" allowfullscreen=\"allowfullscreen\"\n sandbox=\"allow-popups allow-forms allow-scripts allow-same-origin\">\n </iframe>\n <footer id=\"footer\">\n <a target=\"blank\" rel=\"nofollow noopener\" href=\"https://{{ site.github.owner_name }}.github.io/{{ site.github.repository_name }}/README\">Manual</a>\n <a target=\"blank\" rel=\"nofollow noopener\" href=\"https://arcade.makecode.com/#pub:github:{{ site.github.owner_name }}/{{ site.github.repository_name }}\">Edit</a>\n <a target=\"blank\" rel=\"nofollow noopener\" href=\"https://github.com/{{ site.github.owner_name }}/{{ site.github.repository_name }}\">GitHub</a>\n <span id=\"version\"></span>\n <div id=\"fullscreen\">⇲</div>\n </footer>\n <script type=\"text/javascript\">\n makeCodeRun({ js: \"./assets/js/binary.js?v={{ site.github.build_revision }}\" });\n\n if (window.location && window.location.search) {\n var noFooter = /nofooter=1/i.test(window.location.search);\n var embed = /embed=1/i.test(window.location.search);\n var root = document.querySelector(\"#root\");\n\n if (noFooter) {\n var footer = document.querySelector(\"#footer\");\n if (root)\n root.className += \" nofooter\";\n if (footer)\n footer.remove();\n }\n\n if (embed && root) {\n root.className += \" embed\";\n }\n }\n </script>\n</body>\n\n</html>\n",
2220
- "pxt.json": "{\n \"name\": \"template\",\n \"description\": \"Contains overriden or additional files for the default project template\",\n \"dependencies\": {\n \"device\": \"*\"\n },\n \"files\": [\n \"index.html\",\n \".gitattributes\",\n \"assets/index.html\",\n \"assets/js/loader.js\",\n \"assets/js/custom.js\",\n \".github/workflows/makecode-release.yml\"\n ],\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n"
2220
+ "pxt.json": "{\n \"name\": \"template\",\n \"description\": \"Contains overriden or additional files for the default project template\",\n \"dependencies\": {\n \"device\": \"*\"\n },\n \"files\": [\n \"index.html\",\n \".gitattributes\",\n \"assets/index.html\",\n \"assets/js/loader.js\",\n \"assets/js/custom.js\",\n \".github/workflows/makecode-release.yml\"\n ],\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n"
2221
2221
  },
2222
2222
  "thermometer": {
2223
2223
  "README.md": "# temperature\n\nThe temperature library.\n\n",
2224
2224
  "enums.d.ts": "// Auto-generated. Do not edit.\n\n\n declare const enum TemperatureCondition {\n //% block=\"hot\"\n Hot = 2, // SENSOR_THRESHOLD_HIGH\n //% block=\"cold\"\n Cold = 1, // SENSOR_THRESHOLD_LOW\n }\n\n\n declare const enum TemperatureUnit {\n //% block=\"°C\"\n Celsius = 0,\n //% block=\"°F\"\n Fahrenheit = 1,\n }\n\n// Auto-generated. Do not edit. Really.\n",
2225
2225
  "ns.ts": "\n//% color=\"#B4009E\" weight=98 icon=\"\\uf192\"\nnamespace input {\n}",
2226
- "pxt.json": "{\n \"name\": \"thermometer\",\n \"description\": \"A thermometer driver\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"temperature.cpp\",\n \"target_temperature.h\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.12.16\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2226
+ "pxt.json": "{\n \"name\": \"thermometer\",\n \"description\": \"A thermometer driver\",\n \"dependencies\": {\n \"core\": \"*\"\n },\n \"files\": [\n \"README.md\",\n \"temperature.cpp\",\n \"target_temperature.h\",\n \"shims.d.ts\",\n \"enums.d.ts\",\n \"ns.ts\"\n ],\n \"testFiles\": [\n \"test.ts\"\n ],\n \"public\": true,\n \"targetVersions\": {\n \"target\": \"1.13.1\",\n \"pxt\": \"8.5.22\"\n },\n \"hidden\": true\n}\n",
2227
2227
  "shims.d.ts": "// Auto-generated. Do not edit.\ndeclare namespace input {\n\n /**\n * Run some code when the temperature changes from hot to cold, or from cold to hot.\n * @param condition the condition, hot or cold, the event triggers on\n * @param temperature the temperature at which this event happens, eg: 15\n * @param unit the unit of the temperature\n */\n //% blockId=input_on_temperature_condition_changed block=\"on temperature %condition|at %temperature|%unit\"\n //% parts=\"thermometer\"\n //% help=input/on-temperature-condition-changed blockExternalInputs=0\n //% group=\"More\" weight=76 shim=input::onTemperatureConditionChanged\n function onTemperatureConditionChanged(condition: TemperatureCondition, temperature: int32, unit: TemperatureUnit, handler: () => void): void;\n\n /**\n * Get the temperature in Celsius or Fahrenheit degrees.\n */\n //% help=input/temperature\n //% blockId=device_temperature block=\"temperature in %unit\"\n //% parts=\"thermometer\"\n //% weight=26 shim=input::temperature\n function temperature(unit: TemperatureUnit): int32;\n}\n\n// Auto-generated. Do not edit. Really.\n",
2228
2228
  "target_temperature.h": "#include \"NonLinearAnalogSensor.h\"\n\n/*\n * @param nominalValue The value (in SI units) of a nominal position.\n * @param nominalReading The raw reading from the sensor at the nominal position.\n * @param beta The Steinhart-Hart Beta constant for the device\n * @param seriesResistor The value (in ohms) of the resistor in series with the sensor.\n * @param zeroOffset Optional zero offset applied to all SI units (e.g. 273.15 for temperature\n * sensing in C vs Kelvin).\n */\n\n#ifndef TEMPERATURE_NOMINAL_VALUE\n#define TEMPERATURE_NOMINAL_VALUE 25\n#endif\n\n#ifndef TEMPERATURE_NOMINAL_READING\n#define TEMPERATURE_NOMINAL_READING 10000\n#endif\n\n#ifndef TEMPERATURE_BETA\n#define TEMPERATURE_BETA 3380\n#endif\n\n#ifndef TEMPERATURE_SERIES_RESISTOR\n#define TEMPERATURE_SERIES_RESISTOR 10000\n#endif\n\n#ifndef TEMPERATURE_ZERO_OFFSET\n#define TEMPERATURE_ZERO_OFFSET 273.5\n#endif\n\nnamespace pxt {\nclass WTemp {\n public:\n NonLinearAnalogSensor sensor;\n WTemp()\n : sensor(*LOOKUP_PIN(TEMPERATURE), DEVICE_ID_THERMOMETER,\n TEMPERATURE_NOMINAL_VALUE, \n TEMPERATURE_NOMINAL_READING, \n TEMPERATURE_BETA, \n TEMPERATURE_SERIES_RESISTOR,\n TEMPERATURE_ZERO_OFFSET)\n {\n sensor.init();\n }\n};\n}",
2229
2229
  "temperature.cpp": "#include \"pxt.h\"\n#include \"target_temperature.h\"\n\nenum class TemperatureCondition {\n //% block=\"hot\"\n Hot = SENSOR_THRESHOLD_HIGH,\n //% block=\"cold\"\n Cold = SENSOR_THRESHOLD_LOW\n};\n\nenum class TemperatureUnit {\n //% block=\"°C\"\n Celsius,\n //% block=\"°F\"\n Fahrenheit\n};\n\nnamespace pxt {\nSINGLETON_IF_PIN(WTemp, TEMPERATURE);\n}\n\nnamespace input {\n\n/**\n* Run some code when the temperature changes from hot to cold, or from cold to hot.\n* @param condition the condition, hot or cold, the event triggers on\n* @param temperature the temperature at which this event happens, eg: 15\n* @param unit the unit of the temperature\n*/\n//% blockId=input_on_temperature_condition_changed block=\"on temperature %condition|at %temperature|%unit\"\n//% parts=\"thermometer\"\n//% help=input/on-temperature-condition-changed blockExternalInputs=0\n//% group=\"More\" weight=76\nvoid onTemperatureConditionChanged(TemperatureCondition condition, int temperature, TemperatureUnit unit, Action handler) {\n auto thermo = getWTemp();\n if (!thermo) return;\n\n auto sensor = &thermo->sensor;\n sensor->updateSample();\n\n int t = unit == TemperatureUnit::Celsius ? temperature : ((temperature - 32) * 10) / 18;\n\n if (condition == TemperatureCondition::Cold)\n sensor->setLowThreshold(t);\n else\n sensor->setHighThreshold(t);\n registerWithDal(sensor->id, (int)condition, handler);\n}\n\n/**\n * Get the temperature in Celsius or Fahrenheit degrees.\n */\n//% help=input/temperature\n//% blockId=device_temperature block=\"temperature in %unit\"\n//% parts=\"thermometer\"\n//% weight=26\nint temperature(TemperatureUnit unit) {\n auto thermo = getWTemp();\n // default to 21 if not present\n int value = (NULL != thermo) ? thermo->sensor.getValue() : 21;\n if (unit == TemperatureUnit::Celsius) return value;\n else return (value * 18) / 10 + 32;\n}\n}\n",