Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
4e99cd3ef1 | |||
57647318c4 | |||
2720698864 | |||
c0bab4877a | |||
d2a1d10ada | |||
bcb68d937d | |||
05a8395028 | |||
3a1601a419 | |||
712c2178d2 | |||
12cdad72c8 | |||
95076f8f24 | |||
6391620373 | |||
86212e2153 | |||
98e430f3c1 | |||
5c7e856e7b | |||
a47988913e | |||
ea72dba6c7 | |||
215e846a54 | |||
21b34cb459 | |||
282134f5dc | |||
6b44352839 | |||
9a883d5672 | |||
59ce4338d3 | |||
90560050b8 | |||
2c72173bfe | |||
1a5992408b | |||
0e1a3b7e6b | |||
ea6bfa03bd | |||
20d584db2b | |||
0e4e0d8899 | |||
a18a690417 | |||
c9d57c5e8d | |||
7e9d42a571 | |||
1b51320edb | |||
4f44238237 | |||
c8ffa0ded7 | |||
6b07d5f716 | |||
8784e23b60 | |||
4b8409fbc0 | |||
3237978cba | |||
33c8902050 | |||
fa6c81cf80 | |||
46175fc7db | |||
e6ef86101f | |||
c4d3d7634e | |||
b0380fbef8 | |||
c85c68ab68 | |||
334d5aca9a | |||
1330a0fb82 | |||
005447ce44 | |||
60d5271de2 | |||
e3ab6ace55 | |||
5f4488dea7 | |||
07dc3bdae1 | |||
5d5d78ced0 | |||
fe46461c4c | |||
ccda971fd1 | |||
8fa6cf41ca | |||
aa3c6d5fc0 | |||
6a719e7718 | |||
b18b8333d0 | |||
84d80131d4 | |||
4977358718 | |||
15b2ef6c92 | |||
e0288ed741 | |||
df1caf9741 | |||
a755420d06 |
1
.gitignore
vendored
@ -31,3 +31,4 @@ videos/**
|
||||
lib/
|
||||
.vscode/
|
||||
bin
|
||||
scripts/out.*
|
||||
|
@ -1,6 +1,6 @@
|
||||
# LEGO Mindstorms EV3 target for PXT
|
||||
|
||||
[](https://ci2.dot.net/job/Private/job/pxt_project_pink/job/master/job/pxt-ev3_Push/)
|
||||
[](https://ci2.dot.net/job/Private/job/pxt_project_rainbow/job/master/job/pxt-ev3_Push/)
|
||||
|
||||
This repo contains the editor target hosted at https://d541eec2-1e96-4b7b-a223-da9d01d0337a.pxt.io/
|
||||
|
||||
|
@ -3,9 +3,3 @@
|
||||
## Reference #reference
|
||||
|
||||
* [Reference](/reference)
|
||||
* [input](/reference/input)
|
||||
* [light](/reference/light)
|
||||
* [music](/reference/music)
|
||||
* [pins](/reference/pins)
|
||||
* [control](/reference/control)
|
||||
* [serial](/reference/serial)
|
||||
|
47
docs/maker.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Maker Activites
|
||||
|
||||
These six activities require the LEGO® MINDSTORMS® Education EV3 Core Set (45544). Supporting materials for teachers and middle school students are provided, offering everything teachers and students need to explore their inner makers as they follow the design process to solve open-ended, themed challenges...
|
||||
|
||||
* [Download Curriculum Materials](https://education.lego.com/en-us/downloads/mindstorms-ev3)
|
||||
|
||||
## Activites
|
||||
|
||||
```codecard
|
||||
[
|
||||
{
|
||||
"name": "Sound Machine",
|
||||
"description": "Create instruments with your EV3 Brick!",
|
||||
"url":"/maker/sound-machine",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/sound-machine.png"
|
||||
},
|
||||
{
|
||||
"name": "Sound Of Color",
|
||||
"description": "Play different sounds based on the color",
|
||||
"url":"/maker/sound-of-color",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/sound-of-color.png"
|
||||
},
|
||||
{
|
||||
"name": "Security Gadget",
|
||||
"description": "Raise the alarm when your brick is lifted!",
|
||||
"url":"/maker/security-gadget",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/security-gadget.png"
|
||||
},
|
||||
{
|
||||
"name": "Intruder Detector",
|
||||
"description": "Raise the alarm when an intruder sneaks in",
|
||||
"url":"/maker/intruder-detector",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/intruder-detector.png"
|
||||
},
|
||||
{
|
||||
"name": "Puppet",
|
||||
"description": "Build an automated puppet",
|
||||
"url":"/maker/puppet",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/puppet.png"
|
||||
}
|
||||
]
|
||||
```
|
11
docs/maker/intruder-detector.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Intruder Detector
|
||||
|
||||
This program will activate an alarm when an object moves in front of the Ultrasonic Sensor.
|
||||
|
||||
TODO support for event when value changes
|
||||
|
||||
```blocks
|
||||
input.ultrasonic4.onObjectNear(function () {
|
||||
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
|
||||
})
|
||||
```
|
17
docs/maker/puppet.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Puppet
|
||||
|
||||
Use this program with the Programmable Brick and Large Motor.
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
output.largeMotorA.setPower(30)
|
||||
output.largeMotorA.on(true)
|
||||
loops.pause(100)
|
||||
output.largeMotorA.on(false)
|
||||
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
|
||||
output.largeMotorA.setPower(-30)
|
||||
output.largeMotorA.on(true)
|
||||
loops.pause(100)
|
||||
output.largeMotorA.on(false)
|
||||
})
|
||||
```
|
9
docs/maker/security-gadget.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Security Gadget
|
||||
|
||||
This program will activate an alarm when an object is lifted from the Touch Sensor.
|
||||
|
||||
```blocks
|
||||
input.touchSensor1.onEvent(TouchSensorEvent.Released, function () {
|
||||
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
|
||||
})
|
||||
```
|
12
docs/maker/sound-machine.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Sound Machine
|
||||
|
||||
This example program combined with the small model will make a beat and rhythm on any surface when the program is run.
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
output.motorA.on(50)
|
||||
loops.pause(200)
|
||||
output.motorA.on(100)
|
||||
loops.pause(200)
|
||||
})
|
||||
```
|
15
docs/maker/sound-of-color.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Sound Of Color
|
||||
|
||||
This program will play different sounds when the wheel is rotated. The sound is determined by which color is placed in front of the color Sensor.
|
||||
|
||||
```blocks
|
||||
input.color3.onColorDetected(ColorSensorColor.Blue, function () {
|
||||
music.playTone(Note.G4, music.beat(BeatFraction.Half))
|
||||
})
|
||||
input.color3.onColorDetected(ColorSensorColor.Red, function () {
|
||||
music.playTone(Note.C5, music.beat(BeatFraction.Half))
|
||||
})
|
||||
input.color3.onColorDetected(ColorSensorColor.Green, function () {
|
||||
music.playTone(Note.D5, music.beat(BeatFraction.Half))
|
||||
})
|
||||
```
|
@ -1,19 +1,3 @@
|
||||
# Reference
|
||||
|
||||
```namespaces
|
||||
input.onGesture(Gesture.Shake, () => {})
|
||||
light.showRing('red red red red red red red red red red')
|
||||
music.playTone(0, 0)
|
||||
pins.pulseDuration()
|
||||
control.runInBackground(() => {})
|
||||
serial.writeLine("");
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
[blocks](/blocks), [JavaScript](/javascript), [input](/reference/input), [light](/reference/light), [music](/reference/music),
|
||||
[control](/reference/control), [pins](/reference/pins), [serial](/reference/serial)
|
||||
|
||||
```package
|
||||
circuit-playground
|
||||
```
|
||||
TODO
|
BIN
docs/static/hero.png
vendored
Normal file
After Width: | Height: | Size: 40 KiB |
74
docs/static/lego-logo.svg
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="141.73"
|
||||
height="141.731"
|
||||
viewBox="0 0 141.73 141.73101"
|
||||
enable-background="new 0 0 265.365 141.732"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="lego-logo.svg"><metadata
|
||||
id="metadata26"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs24" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1199"
|
||||
inkscape:window-height="604"
|
||||
id="namedview22"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.6520876"
|
||||
inkscape:cx="101.03204"
|
||||
inkscape:cy="98.819336"
|
||||
inkscape:window-x="372"
|
||||
inkscape:window-y="149"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g6" /><g
|
||||
id="product_logo" /><g
|
||||
id="guides" /><g
|
||||
id="LEGO_LOGO_SMALL_RGB"><g
|
||||
id="g6"><path
|
||||
d="m 0.961,0.948 0,139.839 139.84,0 0,-139.839 -139.84,0 z"
|
||||
id="path8"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /><path
|
||||
d="m 0.961,0.948 0,139.839 139.84,0 0,-139.839 -139.84,0 z m 130.536,58.127 c -0.23,4.356 -1.617,9.786 -2.839,13.414 -4.917,14.609 -10.618,23.666 -23.821,23.666 -3.887,0 -10.783,-1.031 -13.324,-7.947 l -0.602,-1.641 -1.082,1.371 C 85.7,93.168 79.564,96.186 72.998,96.217 67.96,96.24 63.912,94.553 61.293,91.334 l -0.718,-0.883 -0.765,0.844 c -2.797,3.088 -7.668,4.859 -13.364,4.859 -4.473,0 -8.335,-1.521 -10.876,-4.277 l -0.692,-0.752 -0.72,0.727 c -2.825,2.852 -7.276,4.289 -12.873,4.158 -6.79,-0.162 -10.924,-3.951 -11.058,-10.141 -0.205,-9.543 9.031,-29.622 12.854,-35.727 2.482,-4.078 5.895,-6.055 10.438,-6.055 3.092,0 5.207,0.646 6.463,1.977 1.144,1.211 1.37,2.232 1.472,4.688 l 0.131,3.175 1.676,-2.7 c 4.054,-6.532 10.773,-7.434 17.43,-7.434 4.628,0 8.667,1.702 10.289,4.336 l 0.599,0.971 0.866,-0.737 c 3.431,-2.916 8.271,-4.521 13.629,-4.521 5.849,0 10.099,1.454 12.634,4.322 0.576,0.651 0.957,1.106 1.486,2.219 l 0.651,1.366 0.977,-1.155 c 3.712,-4.39 8.779,-6.615 15.067,-6.615 4.98,0 8.761,1.324 11.235,3.935 3.104,3.271 3.547,7.875 3.373,11.161 z"
|
||||
id="path10"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f6ec36" /><path
|
||||
d="m 0.961,0.948 0,139.839 139.84,0 0,-139.839 -139.84,0 z M 135.435,64.44 c -0.633,5.089 -4.072,14.518 -5.899,18.286 -4.903,10.102 -11.453,17.863 -24.074,17.863 -6.742,0 -12.288,-2.15 -15.531,-6.283 -4.749,4.162 -10.627,6.342 -16.956,6.342 -4.876,0 -9.185,-1.408 -12.471,-4.012 -3.626,2.555 -8.52,3.98 -13.943,3.98 -4.53,0 -8.606,-1.244 -11.796,-3.543 -3.529,2.342 -8.154,3.506 -13.583,3.377 C 12.149,100.237 5.912,94.507 5.733,86.188 5.497,75.137 14.803,54.911 19.189,47.907 c 3.282,-5.392 8.292,-8.293 14.431,-8.293 6.663,0 9.078,1.903 10.267,4.326 5.141,-4.366 11.956,-4.617 16.808,-4.617 5.356,0 8.717,1.422 11.575,3.697 3.948,-2.368 8.477,-3.599 13.871,-3.599 6.897,0 12.021,1.604 15.595,5.137 4.168,-3.469 9.388,-5.05 15.23,-5.05 7.725,0 12.808,2.786 15.793,6.94 4.203,5.859 3.451,11.757 2.676,17.992 z"
|
||||
id="path12"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#d01012" /><path
|
||||
d="m 0,0 0,141.731 141.73,0 L 141.73,0 0,0 Z m 139.781,1.952 0,137.832 -137.83,0 0,-137.832 137.83,0 z"
|
||||
id="path14"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 134.752,42.53 0,-0.965 0.655,0 c 0.479,0 0.728,0.168 0.728,0.479 0,0.247 -0.16,0.486 -0.647,0.486 l -0.736,0 z m 2.351,2.002 -0.408,-0.708 c -0.354,-0.619 -0.452,-0.717 -0.755,-0.823 l 0,-0.019 c 0.596,-0.07 0.95,-0.453 0.95,-0.983 0,-0.56 -0.354,-0.984 -1.109,-0.984 l -1.754,0 0,3.519 0.727,0 0,-1.441 0.133,0 c 0.311,0 0.435,0.035 0.576,0.176 0.142,0.144 0.354,0.443 0.479,0.69 l 0.284,0.575 0.877,-0.002 0,0 z m -1.731,-4.497 c 1.51,0 2.737,1.218 2.737,2.726 0,1.508 -1.229,2.731 -2.737,2.731 -1.506,0 -2.72,-1.225 -2.72,-2.731 0,-1.506 1.214,-2.726 2.72,-2.726 z m 0,-0.67 c -1.877,0 -3.392,1.516 -3.392,3.396 0,1.879 1.515,3.394 3.392,3.394 1.883,0 3.397,-1.515 3.397,-3.394 0.002,-1.882 -1.514,-3.396 -3.397,-3.396 z"
|
||||
id="path16"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 116.889,43.002 c -7.325,0 -12.386,2.904 -15.812,6.961 -0.579,-1.214 -1.019,-1.746 -1.638,-2.447 -2.805,-3.17 -7.313,-4.649 -13.364,-4.649 -5.912,0 -10.841,1.846 -14.263,4.754 -1.777,-2.89 -6.013,-4.803 -11.121,-4.803 -6.674,0 -13.946,0.944 -18.261,7.896 -0.104,-2.503 -0.33,-3.828 -1.737,-5.317 -1.71,-1.81 -4.477,-2.282 -7.173,-2.282 -4.912,0 -8.605,2.146 -11.266,6.515 -3.859,6.163 -13.212,26.441 -13.001,36.263 0.137,6.344 4.393,10.916 12.01,11.096 5.952,0.143 10.62,-1.449 13.59,-4.447 2.665,2.896 6.731,4.594 11.596,4.594 5.417,0 10.868,-1.627 14.088,-5.182 2.712,3.332 6.979,5.271 12.468,5.244 7.175,-0.035 13.477,-3.438 17.593,-8.652 2.259,6.148 7.985,8.59 14.241,8.59 13.709,0 19.729,-9.428 24.748,-24.332 1.13,-3.357 2.639,-8.963 2.889,-13.672 0.413,-7.839 -2.903,-16.13 -15.587,-16.13 z M 25.672,80.477 c 7.093,-1.232 8.876,1.332 8.653,3.707 -0.669,7.109 -7.191,8.699 -12.854,8.566 -4.107,-0.1 -7.8,-1.98 -7.903,-6.748 -0.18,-8.342 8.328,-27.641 12.333,-34.038 1.85,-3.037 4.104,-4.539 7.698,-4.539 3.406,0 4.25,1.749 4.2,3.844 -0.134,5.589 -9.164,22.574 -12.127,29.208 z M 48.77,73.925 c -0.469,1.27 -1.357,3.93 -2.076,6.75 2.328,-0.582 4.074,-0.986 7.065,-0.914 3.408,0.084 5.586,1.496 5.586,4.314 0,6.832 -7.551,8.838 -12.789,8.838 -5.751,0 -10.803,-3.275 -10.803,-9.564 0,-7.373 3.997,-18.553 7.748,-26.001 4.606,-9.146 9.312,-10.362 17.419,-10.362 3.562,0 7.667,1.524 7.667,4.888 0,4.662 -3.95,6.44 -7.866,6.665 -1.672,0.096 -4.246,0.188 -5.786,0.079 0,0 -1.303,1.985 -2.688,5.523 7.252,-1.021 10.327,0.625 9.103,4.82 -1.657,5.667 -6.567,6.04 -12.58,4.964 z M 84.438,56.293 c -1.961,0 -3.244,1.242 -4.198,2.583 -2.102,2.952 -6.656,14.781 -7.365,19.64 -0.486,3.328 0.951,4.006 2.522,4.006 2.52,0 5.345,-2.666 6.309,-7.064 0,0 -4.797,-0.117 -3.475,-4.371 1.285,-4.128 3.723,-5.022 7.764,-5.188 7.961,-0.325 7.175,5.553 6.538,8.688 -2.069,10.18 -9.314,18.355 -19.562,18.355 -7.016,0 -11.371,-3.881 -11.371,-11.035 0,-5.098 2.529,-13.101 4.534,-17.784 4.267,-9.968 8.742,-16.944 20.143,-16.944 6.84,0 12.235,2.458 11.444,8.866 -0.58,4.703 -2.934,7.465 -7.21,7.799 -1.196,0.093 -6.089,-0.031 -4.466,-4.66 0.565,-1.619 0.799,-2.891 -1.607,-2.891 z m 43.057,8.413 c -1.205,6.002 -3.916,13.101 -6.859,18.392 -4.801,8.633 -10.633,9.842 -15.723,9.781 -5.093,-0.061 -10.83,-1.941 -10.874,-9.795 -0.031,-5.639 2.401,-13.598 4.466,-18.815 3.599,-9.458 7.277,-17.17 18.904,-17.031 13.559,0.161 11.141,12.219 10.086,17.468 z M 115.993,56.49 c -1.164,-0.016 -2.18,0.212 -3.093,1.62 -2.051,2.657 -8.047,19.042 -7.941,22.31 0.038,1.174 0.687,2.201 2.133,2.201 1.659,0.002 2.581,-1.145 3.396,-2.529 1.887,-3.193 7.193,-17.676 7.339,-21.297 0.043,-1.055 -0.133,-2.284 -1.834,-2.305 z"
|
||||
id="path18"
|
||||
inkscape:connector-curvature="0" /></g></g></svg>
|
After Width: | Height: | Size: 7.7 KiB |
BIN
docs/static/lego_education_logo.png
vendored
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
docs/static/maker/intruder-detector.png
vendored
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
docs/static/maker/puppet.png
vendored
Normal file
After Width: | Height: | Size: 377 KiB |
BIN
docs/static/maker/security-gadget.png
vendored
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
docs/static/maker/sound-machine.png
vendored
Normal file
After Width: | Height: | Size: 141 KiB |
BIN
docs/static/maker/sound-of-color.png
vendored
Normal file
After Width: | Height: | Size: 159 KiB |
@ -31,6 +31,22 @@
|
||||
"Array.splice|param|deleteCount": "The number of elements to remove. eg: 0",
|
||||
"Array.splice|param|start": "The zero-based location in the array from which to start removing elements. eg: 0",
|
||||
"Array.unshift": "Add one element to the beginning of an array and return the new length of the array.",
|
||||
"Boolean.toString": "Returns a string representation of an object.",
|
||||
"Buffer.fill": "Fill (a fragment) of the buffer with given value.",
|
||||
"Buffer.getNumber": "Read a number in specified format from the buffer.",
|
||||
"Buffer.length": "Returns the length of a Buffer object.",
|
||||
"Buffer.rotate": "Rotate buffer left in place.\n\n\n\nstart. eg: -1",
|
||||
"Buffer.rotate|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus",
|
||||
"Buffer.rotate|param|offset": "number of bytes to shift; use negative value to shift right",
|
||||
"Buffer.rotate|param|start": "start offset in buffer. Default is 0.",
|
||||
"Buffer.setNumber": "Write a number in specified format in the buffer.",
|
||||
"Buffer.shift": "Shift buffer left in place, with zero padding.\n\n\n\nstart. eg: -1",
|
||||
"Buffer.shift|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus",
|
||||
"Buffer.shift|param|offset": "number of bytes to shift; use negative value to shift right",
|
||||
"Buffer.shift|param|start": "start offset in buffer. Default is 0.",
|
||||
"Buffer.slice": "Return a copy of a fragment of a buffer.",
|
||||
"Buffer.toHex": "Convert a buffer to its hexadecimal representation.",
|
||||
"Buffer.write": "Write contents of `src` at `dstOffset` in current buffer.",
|
||||
"Math": "More complex operations with numbers.",
|
||||
"Math.abs": "Returns the absolute value of a number (the value without regard to whether it is positive or negative).\nFor example, the absolute value of -5 is the same as the absolute value of 5.",
|
||||
"Math.abs|param|x": "A numeric expression for which the absolute value is needed.",
|
||||
@ -91,6 +107,7 @@
|
||||
"Math.tan|param|x": "An angle in radians",
|
||||
"Math.trunc": "Returns the number with the decimal part truncated.",
|
||||
"Math.trunc|param|x": "A numeric expression.",
|
||||
"Number.toString": "Returns a string representation of a number.",
|
||||
"String": "Combine, split, and search text strings.\n\nCombine, split, and search text strings.",
|
||||
"String.charAt": "Return the character at the specified index.",
|
||||
"String.charAt|param|index": "The zero-based index of the desired character.",
|
||||
@ -107,6 +124,8 @@
|
||||
"String.substr|param|length": "number of characters to extract",
|
||||
"String.substr|param|start": "first character index; can be negative from counting from the end, eg:0",
|
||||
"control": "Program controls and events.",
|
||||
"control.AnimationQueue.cancel": "Cancels the current running animation and clears the queue",
|
||||
"control.AnimationQueue.runUntilDone": "Runs 'render' in a loop until it returns false or the 'stop' function is called",
|
||||
"control.assert": "Display an error code and stop the program when the assertion is `false`.",
|
||||
"control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.",
|
||||
"control.millis": "Gets the number of milliseconds elapsed since power on.",
|
||||
@ -119,9 +138,13 @@
|
||||
"control.waitForEvent": "Blocks the calling thread until the specified event is raised.",
|
||||
"control.waitMicros": "Block the current fiber for the given microseconds",
|
||||
"control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4",
|
||||
"hex": "Tagged hex literal converter",
|
||||
"loops.forever": "Repeats the code forever in the background. On each iteration, allows other codes to run.",
|
||||
"loops.pause": "Pause for the specified time in milliseconds",
|
||||
"loops.pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000",
|
||||
"loops.timePicker": "Get the time field editor",
|
||||
"loops.timePicker|param|ms": "time duration in milliseconds, eg: 500, 1000",
|
||||
"parseInt": "Convert a string to an integer.",
|
||||
"serial": "Reading and writing data over a serial connection.",
|
||||
"serial.writeBuffer": "Send a buffer across the serial connection.",
|
||||
"serial.writeLine": "Write a line of text to the serial port.",
|
||||
|
@ -10,7 +10,7 @@
|
||||
"Array.unshift|block": "%list| insert %value| at beginning",
|
||||
"Array|block": "Array",
|
||||
"Math.constrain|block": "constrain %value|between %low|and %high",
|
||||
"Math.map|block": "map %value|from %fromLow|%fromHigh|to %toLow|%toHigh",
|
||||
"Math.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh",
|
||||
"Math.randomRange|block": "pick random %min|to %limit",
|
||||
"Math|block": "Math",
|
||||
"String.charAt|block": "char from %this=text|at %pos",
|
||||
@ -30,8 +30,10 @@
|
||||
"control.waitMicros|block": "wait (µs)%micros",
|
||||
"control|block": "control",
|
||||
"loops.forever|block": "forever",
|
||||
"loops.pause|block": "pause (ms) %pause",
|
||||
"loops.pause|block": "pause %ms=timePicker|ms",
|
||||
"loops.timePicker|block": "%ms",
|
||||
"loops|block": "loops",
|
||||
"parseInt|block": "parse to integer %text",
|
||||
"serial.writeBuffer|block": "serial|write buffer %buffer",
|
||||
"serial.writeLine|block": "serial|write line %text",
|
||||
"serial.writeNumber|block": "serial|write number %value",
|
||||
@ -40,9 +42,13 @@
|
||||
"serial|block": "serial",
|
||||
"{id:category}Array": "Array",
|
||||
"{id:category}Arrays": "Arrays",
|
||||
"{id:category}Boolean": "Boolean",
|
||||
"{id:category}Buffer": "Buffer",
|
||||
"{id:category}Control": "Control",
|
||||
"{id:category}Helpers": "Helpers",
|
||||
"{id:category}Loops": "Loops",
|
||||
"{id:category}Math": "Math",
|
||||
"{id:category}Number": "Number",
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:category}String": "String",
|
||||
"{id:category}Text": "Text"
|
||||
|
8
libs/base/shims.d.ts
vendored
@ -70,7 +70,7 @@ declare namespace loops {
|
||||
* Repeats the code forever in the background. On each iteration, allows other codes to run.
|
||||
* @param body code to execute
|
||||
*/
|
||||
//% help=loops/forever weight=100 blockGap=8
|
||||
//% help=loops/forever weight=100 afterOnStart=true
|
||||
//% blockId=forever block="forever" blockAllowMultiple=1 shim=loops::forever
|
||||
function forever(a: () => void): void;
|
||||
|
||||
@ -79,7 +79,7 @@ declare namespace loops {
|
||||
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
|
||||
*/
|
||||
//% help=loops/pause weight=99
|
||||
//% async block="pause (ms) %pause"
|
||||
//% async block="pause %ms=timePicker|ms"
|
||||
//% blockId=device_pause shim=loops::pause
|
||||
function pause(ms: int32): void;
|
||||
}
|
||||
@ -120,7 +120,7 @@ declare namespace control {
|
||||
/**
|
||||
* Run other code in the background.
|
||||
*/
|
||||
//% help=control/run-in-background blockAllowMultiple=1
|
||||
//% help=control/run-in-background blockAllowMultiple=1 afterOnStart=true
|
||||
//% blockId="control_run_in_background" block="run in background" blockGap=8 shim=control::runInBackground
|
||||
function runInBackground(a: () => void): void;
|
||||
|
||||
@ -151,7 +151,7 @@ declare namespace serial {
|
||||
/**
|
||||
* Send a buffer across the serial connection.
|
||||
*/
|
||||
//% help=serial/write-buffer advanced=true weight=6
|
||||
//% help=serial/write-buffer weight=6
|
||||
//% blockId=serial_writebuffer block="serial|write buffer %buffer" shim=serial::writeBuffer
|
||||
function writeBuffer(buffer: Buffer): void;
|
||||
}
|
||||
|
@ -1,4 +1,15 @@
|
||||
{
|
||||
"ButtonEvent": "User interaction on buttons",
|
||||
"Draw": "Drawing modes",
|
||||
"LightsPattern": "Patterns for lights under the buttons.",
|
||||
"MMap.getNumber": "Read a number in specified format from the buffer.",
|
||||
"MMap.ioctl": "Perform ioctl(2) on the underlaying file",
|
||||
"MMap.length": "Returns the length of a Buffer object.",
|
||||
"MMap.read": "Perform read(2) on the underlaying file",
|
||||
"MMap.setNumber": "Write a number in specified format in the buffer.",
|
||||
"MMap.slice": "Read a range of bytes into a buffer.",
|
||||
"MMap.write": "Perform write(2) on the underlaying file",
|
||||
"TouchSensorEvent": "Touch sensor interactions",
|
||||
"control": "Program controls and events.",
|
||||
"control.allocateNotifyEvent": "Allocates the next user notification event",
|
||||
"control.deviceFirmwareVersion": "Determine the version of system software currently running.",
|
||||
@ -9,45 +20,71 @@
|
||||
"control.raiseEvent|param|value": "Component specific code indicating the cause of the event.",
|
||||
"input": "Respond to and read data from buttons and sensors.",
|
||||
"input.Button": "Generic button class, for device buttons and sensors.",
|
||||
"input.buttonDown": "Down button.",
|
||||
"input.buttonEnter": "Enter button.",
|
||||
"input.buttonLeft": "Left button.",
|
||||
"input.buttonRight": "Right button.",
|
||||
"input.buttonUp": "Up button.",
|
||||
"input.remoteBottomLeft": "Remote bottom-left button.",
|
||||
"input.remoteBottomRight": "Remote bottom-right button.",
|
||||
"input.remoteCenter": "Remote beacon (center) button.",
|
||||
"input.remoteTopLeft": "Remote top-left button.",
|
||||
"input.remoteTopRight": "Remote top-right button.",
|
||||
"input.Button.isPressed": "Check if button is currently pressed or not.",
|
||||
"input.Button.onEvent": "Do something when a button or sensor is clicked, up or down.",
|
||||
"input.Button.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
||||
"input.ColorSensor.ambientLight": "Get current ambient light value from the color sensor.",
|
||||
"input.ColorSensor.color": "Get the current color from the color sensor.",
|
||||
"input.ColorSensor.onColorDetected": "Registers code to run when the given color is detected",
|
||||
"input.ColorSensor.onColorDetected|param|color": "the color to dtect",
|
||||
"input.ColorSensor.onColorDetected|param|handler": "the code to run when detected",
|
||||
"input.ColorSensor.reflectedLight": "Get current reflected light value from the color sensor.",
|
||||
"input.GyroSensor.angle": "Get the current angle from the gyroscope.",
|
||||
"input.GyroSensor.rate": "Get the current rotation rate from the gyroscope.",
|
||||
"input.InfraredSensor.onObjectNear": "Registers code to run when an object is getting near.",
|
||||
"input.InfraredSensor.onObjectNear|param|handler": "the code to run when detected",
|
||||
"input.InfraredSensor.proximity": "Get the promixity measured by the infrared sensor, from ``0`` (close) to ``100`` (far)",
|
||||
"input.InfraredSensor.remoteCommand": "Get the remote commandreceived the infrared sensor.",
|
||||
"input.RemoteInfraredBeaconButton.isPressed": "Check if a remote button is currently pressed or not.",
|
||||
"input.RemoteInfraredBeaconButton.onEvent": "Do something when a button or sensor is clicked, up or down",
|
||||
"input.RemoteInfraredBeaconButton.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.RemoteInfraredBeaconButton.wasPressed": "See if the remote button was pressed again since the last time you checked.",
|
||||
"input.TouchSensor.isTouched": "Check if touch sensor is touched.",
|
||||
"input.TouchSensor.onEvent": "Do something when a touch sensor is touched...",
|
||||
"input.TouchSensor.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.UltraSonicSensor.distance": "Gets the distance from the sonar in millimeters",
|
||||
"input.UltraSonicSensor.onObjectNear": "Registers code to run when the given color is close",
|
||||
"input.UltraSonicSensor.onObjectNear|param|handler": "the code to run when detected",
|
||||
"input.buttonDown": "Down button on the EV3 Brick.",
|
||||
"input.buttonEnter": "Enter button on the EV3 Brick.",
|
||||
"input.buttonLeft": "Left button on the EV3 Brick.",
|
||||
"input.buttonRight": "Right button on the EV3 Brick.",
|
||||
"input.buttonUp": "Up button on the EV3 Brick.",
|
||||
"input.remoteButtonBottomLeft": "Remote bottom-left button.",
|
||||
"input.remoteButtonBottomRight": "Remote bottom-right button.",
|
||||
"input.remoteButtonCenter": "Remote beacon (center) button.",
|
||||
"input.remoteButtonTopLeft": "Remote top-left button.",
|
||||
"input.remoteButtonTopRight": "Remote top-right button.",
|
||||
"output.Motor.clearCount": "Clears the motor count",
|
||||
"output.Motor.count": "Gets motor step count.",
|
||||
"output.Motor.on": "Power on or off the motor.",
|
||||
"output.Motor.reset": "Resets the motor.",
|
||||
"output.Motor.setBrake": "Sets the automatic brake on or off when the motor is off",
|
||||
"output.Motor.setBrake|param|brake": "a value indicating if the motor should break when off",
|
||||
"output.Motor.setPower": "Sets the motor power level from ``-100`` to ``100``.",
|
||||
"output.Motor.setPower|param|power": "the desired speed to use. eg: 50",
|
||||
"output.Motor.setReversed": "Reverses the motor polarity",
|
||||
"output.Motor.speed": "Gets motor actual speed.",
|
||||
"output.Motor.tachoCount": "Gets motor tacho count.",
|
||||
"output.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"output.createBuffer|param|size": "number of bytes in the buffer",
|
||||
"output.getCurrentSpeed": "Get motor speed.",
|
||||
"output.getCurrentSpeed|param|out": "the output connection that the motor is connected to",
|
||||
"output.getPattern": "Pattern block.",
|
||||
"output.getPattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||
"output.setLights": "Set lights.",
|
||||
"output.setLights|param|pattern": "the lights pattern to use.",
|
||||
"output.setPower": "Set motor power.",
|
||||
"output.setPower|param|out": "the output connection that the motor is connected to",
|
||||
"output.setPower|param|power": "the desired power to use. eg: 100",
|
||||
"output.setSpeed": "Set motor speed.",
|
||||
"output.setSpeed|param|out": "the output connection that the motor is connected to",
|
||||
"output.setSpeed|param|speed": "the desired speed to use. eg: 100",
|
||||
"output.start": "Turn motor on.",
|
||||
"output.start|param|out": "the output connection that the motor is connected to",
|
||||
"output.stop": "Turn motor off.",
|
||||
"output.stop|param|out": "the output connection that the motor is connected to",
|
||||
"output.turn": "Turn a motor on for a specified number of milliseconds.",
|
||||
"output.turn|param|ms": "the number of milliseconds to turn the motor on, eg: 500",
|
||||
"output.turn|param|out": "the output connection that the motor is connected to",
|
||||
"output.turn|param|useBrake": "whether or not to use the brake, defaults to false",
|
||||
"output.pattern": "Pattern block.",
|
||||
"output.pattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||
"output.setStatusLight": "Set lights.",
|
||||
"output.setStatusLight|param|pattern": "the lights pattern to use.",
|
||||
"output.stopAllMotors": "Stops all motors",
|
||||
"screen.clear": "Clear screen and reset font to normal.",
|
||||
"screen.doubleIcon": "Double size of an icon.",
|
||||
"screen.drawIcon": "Draw an icon on the screen.",
|
||||
"screen.drawText": "Show text on the screen.",
|
||||
"screen.drawText|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||
"screen.drawText|param|x": "the starting position's x coordinate, eg: 0",
|
||||
"screen.drawText|param|y": "the starting position's x coordinate, eg: 0",
|
||||
"screen.print": "Show text on the screen.",
|
||||
"screen.print|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||
"screen.print|param|x": "the starting position's x coordinate, eg: 0",
|
||||
"screen.print|param|y": "the starting position's x coordinate, eg: 0",
|
||||
"screen.setPixel": "Sets a pixel on or off",
|
||||
"screen.setPixel|param|on": "a value indicating if the pixel should be on or off",
|
||||
"screen.setPixel|param|x": "the starting position's x coordinate, eg: 0",
|
||||
"screen.setPixel|param|y": "the starting position's x coordinate, eg: 0",
|
||||
"serial": "Reading and writing data over a serial connection.",
|
||||
"serial.writeDmesg": "Send DMESG debug buffer over serial."
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
{
|
||||
"ButtonEvent.Click|block": "click",
|
||||
"ButtonEvent.Down|block": "down",
|
||||
"ButtonEvent.LongClick|block": "long click",
|
||||
"ButtonEvent.Up|block": "up",
|
||||
"ColorSensorColor.Black|block": "black",
|
||||
"ColorSensorColor.Blue|block": "blue",
|
||||
"ColorSensorColor.Brown|block": "brown",
|
||||
"ColorSensorColor.Green|block": "green",
|
||||
"ColorSensorColor.None|block": "none",
|
||||
"ColorSensorColor.Red|block": "red",
|
||||
"ColorSensorColor.White|block": "white",
|
||||
"ColorSensorColor.Yellow|block": "yellow",
|
||||
"LightsPattern.GreenFlash|block": "Flashing Green",
|
||||
"LightsPattern.GreenPulse|block": "Pulsing Green",
|
||||
"LightsPattern.Green|block": "Green",
|
||||
@ -13,37 +20,103 @@
|
||||
"LightsPattern.RedFlash|block": "Flashing Red",
|
||||
"LightsPattern.RedPulse|block": "Pulsing Red",
|
||||
"LightsPattern.Red|block": "Red",
|
||||
"Output.ALL|block": "All",
|
||||
"Output.A|block": "A",
|
||||
"Output.B|block": "B",
|
||||
"Output.C|block": "C",
|
||||
"Output.D|block": "D",
|
||||
"PromixityEvent.ObjectDetected|block": "object detected",
|
||||
"PromixityEvent.ObjectNear|block": "object near",
|
||||
"TouchSensorEvent.Bumped|block": "bumped",
|
||||
"TouchSensorEvent.Pressed|block": "pressed",
|
||||
"TouchSensorEvent.Released|block": "released",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||
"control|block": "control",
|
||||
"input.buttonDown|block": "button down",
|
||||
"input.buttonEnter|block": "button enter",
|
||||
"input.buttonLeft|block": "button left",
|
||||
"input.buttonRight|block": "button right",
|
||||
"input.buttonUp|block": "button up",
|
||||
"input.remoteBottomLeft|block": "remote bottom-left",
|
||||
"input.remoteBottomRight|block": "remote bottom-right",
|
||||
"input.remoteCenter|block": "remote center",
|
||||
"input.remoteTopLeft|block": "remote top-left",
|
||||
"input.remoteTopRight|block": "remote top-right",
|
||||
"input.Button.isPressed|block": "%button|is pressed",
|
||||
"input.Button.onEvent|block": "on %button|%event",
|
||||
"input.Button.wasPressed|block": "%button|was pressed",
|
||||
"input.ColorSensor.ambientLight|block": "%color| ambient light",
|
||||
"input.ColorSensor.color|block": "%color| color",
|
||||
"input.ColorSensor.onColorDetected|block": "on %sensor|detected %color",
|
||||
"input.ColorSensor.reflectedLight|block": "%color| reflected light",
|
||||
"input.GyroSensor.angle|block": "%sensor|angle",
|
||||
"input.GyroSensor.rate|block": "%sensor|rotation rate",
|
||||
"input.InfraredSensor.onObjectNear|block": "on %sensor|object near",
|
||||
"input.InfraredSensor.proximity|block": "%infrared|proximity",
|
||||
"input.InfraredSensor.remoteCommand|block": "%infrared|remote command",
|
||||
"input.RemoteInfraredBeaconButton.isPressed|block": "%button|is pressed",
|
||||
"input.RemoteInfraredBeaconButton.onEvent|block": "on %button|%event",
|
||||
"input.RemoteInfraredBeaconButton.wasPressed|block": "%button|was pressed",
|
||||
"input.TouchSensor.isTouched|block": "%sensor|is touched",
|
||||
"input.TouchSensor.onEvent|block": "on %sensor|%event",
|
||||
"input.UltraSonicSensor.distance|block": "%sensor|distance",
|
||||
"input.UltraSonicSensor.onObjectNear|block": "on %sensor|object near",
|
||||
"input.buttonDown|block": "brick button down",
|
||||
"input.buttonEnter|block": "brick button enter",
|
||||
"input.buttonLeft|block": "brick button left",
|
||||
"input.buttonRight|block": "brick button right",
|
||||
"input.buttonUp|block": "brick button up",
|
||||
"input.color1|block": "color sensor 1",
|
||||
"input.color2|block": "color sensor 2",
|
||||
"input.color3|block": "color sensor 3",
|
||||
"input.color4|block": "color sensor 4",
|
||||
"input.gyro1|block": "gyro sensor 1",
|
||||
"input.gyro2|block": "gyro sensor 2",
|
||||
"input.gyro3|block": "gyro sensor 3",
|
||||
"input.gyro4|block": "gyro sensor 4",
|
||||
"input.infraredSensor1|block": "infrared sensor 1",
|
||||
"input.infraredSensor2|block": "infrared sensor 2",
|
||||
"input.infraredSensor3|block": "infrared sensor 3",
|
||||
"input.infraredSensor4|block": "infrared sensor 4",
|
||||
"input.remoteButtonBottomLeft|block": "remote button bottom-left",
|
||||
"input.remoteButtonBottomRight|block": "remote button bottom-right",
|
||||
"input.remoteButtonCenter|block": "remote button center",
|
||||
"input.remoteButtonTopLeft|block": "remote button top-left",
|
||||
"input.remoteButtonTopRight|block": "remote button top-right",
|
||||
"input.touchSensor1|block": "touch sensor 1",
|
||||
"input.touchSensor2|block": "touch sensor 2",
|
||||
"input.touchSensor3|block": "touch sensor 3",
|
||||
"input.touchSensor4|block": "touch sensor 4",
|
||||
"input.ultrasonic1|block": "ultrasonic sensor 1",
|
||||
"input.ultrasonic2|block": "ultrasonic sensor 2",
|
||||
"input.ultrasonic3|block": "ultrasonic sensor 3",
|
||||
"input.ultrasonic4|block": "ultrasonic sensor 4",
|
||||
"input|block": "input",
|
||||
"output.getCurrentSpeed|block": "motor %out|speed",
|
||||
"output.getPattern|block": "%pattern",
|
||||
"output.setLights|block": "set status light %pattern=led_pattern",
|
||||
"output.setPower|block": "set motor %out| power to %power",
|
||||
"output.setSpeed|block": "set motor %out| speed to %speed",
|
||||
"output.start|block": "turn motor %out|on",
|
||||
"output.stop|block": "turn motor %out|off",
|
||||
"output.turn|block": "turn motor %out| on for %ms|milliseconds",
|
||||
"output.Motor.count|block": "%motor|count",
|
||||
"output.Motor.on|block": "%motor|%onOrOff",
|
||||
"output.Motor.setBrake|block": "%motor|set brake %brake",
|
||||
"output.Motor.setPower|block": "%motor|set power to %speed",
|
||||
"output.Motor.setReversed|block": "%motor|set reversed %reversed",
|
||||
"output.Motor.speed|block": "%motor|speed",
|
||||
"output.Motor.tachoCount|block": "%motor|tacho count",
|
||||
"output.largeMotorA|block": "large motor A",
|
||||
"output.largeMotorB|block": "large motor B",
|
||||
"output.largeMotorC|block": "large motor C",
|
||||
"output.largeMotorD|block": "large motor D",
|
||||
"output.mediumMotorA|block": "medium motor A",
|
||||
"output.mediumMotorB|block": "medium motor B",
|
||||
"output.mediumMotorC|block": "medium motor C",
|
||||
"output.mediumMotorD|block": "medium motor D",
|
||||
"output.pattern|block": "%pattern",
|
||||
"output.setStatusLight|block": "set status light %pattern=led_pattern",
|
||||
"output.stopAllMotors|block": "stop all motors",
|
||||
"output|block": "output",
|
||||
"screen.drawText|block": "print %text| at x: %x| y: %y",
|
||||
"screen.print|block": "print %text| at x: %x| y: %y",
|
||||
"screen.setPixel|block": "set pixel %on| at x: %x| y: %y",
|
||||
"screen|block": "screen",
|
||||
"serial|block": "serial",
|
||||
"{id:category}Control": "Control",
|
||||
"{id:category}Input": "Input",
|
||||
"{id:category}MMap": "MMap",
|
||||
"{id:category}Output": "Output",
|
||||
"{id:category}Screen": "Screen",
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:group}Lights": "Lights",
|
||||
"{id:group}Brick": "Brick",
|
||||
"{id:group}Color Sensor": "Color Sensor",
|
||||
"{id:group}Gyro Sensor": "Gyro Sensor",
|
||||
"{id:group}Infrared Sensor": "Infrared Sensor",
|
||||
"{id:group}Motors": "Motors",
|
||||
"{id:group}Screen": "Screen"
|
||||
"{id:group}Remote Infrared Beacon": "Remote Infrared Beacon",
|
||||
"{id:group}Touch Sensor": "Touch Sensor",
|
||||
"{id:group}Ultrasonic Sensor": "Ultrasonic Sensor"
|
||||
}
|
@ -4,34 +4,34 @@
|
||||
*/
|
||||
const enum LightsPattern {
|
||||
//% block=Off enumval=0
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
Off = 0,
|
||||
//% block=Green enumval=1
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
Green = 1,
|
||||
//% block=Red enumval=2
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
Red = 2,
|
||||
//% block=Orange enumval=3
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
Orange = 3,
|
||||
//% block="Flashing Green" enumval=4
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
GreenFlash = 4,
|
||||
//% block="Flashing Red" enumval=5
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
RedFlash = 5,
|
||||
//% block="Flashing Orange" enumval=6
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
OrangeFlash = 6,
|
||||
//% block="Pulsing Green" enumval=7
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
GreenPulse = 7,
|
||||
//% block="Pulsing Red" enumval=8
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
RedPulse = 8,
|
||||
//% block="Pulsing Orange" enumval=9
|
||||
//% blockIdentity=output.getPattern
|
||||
//% blockIdentity=output.pattern
|
||||
OrangePulse = 9,
|
||||
}
|
||||
|
||||
@ -41,8 +41,6 @@ const enum LightsPattern {
|
||||
const enum ButtonEvent {
|
||||
//% block="click"
|
||||
Click = 1,
|
||||
//% block="long click"
|
||||
LongClick = 2,
|
||||
//% block="up"
|
||||
Up = 3,
|
||||
//% block="down"
|
||||
@ -67,7 +65,7 @@ namespace input {
|
||||
}
|
||||
|
||||
//% hidden
|
||||
update(curr: boolean) {
|
||||
_update(curr: boolean) {
|
||||
if (this._isPressed == curr) return
|
||||
this._isPressed = curr
|
||||
if (curr) {
|
||||
@ -76,7 +74,8 @@ namespace input {
|
||||
} else {
|
||||
control.raiseEvent(this._id, ButtonEvent.Up)
|
||||
let delta = control.millis() - this.downTime
|
||||
control.raiseEvent(this._id, delta > 500 ? ButtonEvent.LongClick : ButtonEvent.Click)
|
||||
control.raiseEvent(this._id, ButtonEvent.Click)
|
||||
//control.raiseEvent(this._id, delta > 500 ? ButtonEvent.LongClick : ButtonEvent.Click)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,16 +83,13 @@ namespace input {
|
||||
* Check if button is currently pressed or not.
|
||||
* @param button the button to query the request
|
||||
*/
|
||||
//% help=input/button/is-pressed weight=79
|
||||
//% help=input/button/is-pressed
|
||||
//% block="%button|is pressed"
|
||||
//% blockId=buttonIsPressed
|
||||
//% blockGap=8
|
||||
//% parts="buttonpair"
|
||||
//% parts="brick"
|
||||
//% blockNamespace=input
|
||||
//% group="Brick buttons"
|
||||
//% button.fieldEditor="gridpicker"
|
||||
//% button.fieldOptions.width=220
|
||||
//% button.fieldOptions.columns=3
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Brick"
|
||||
isPressed() {
|
||||
return this._isPressed
|
||||
}
|
||||
@ -102,15 +98,13 @@ namespace input {
|
||||
* See if the button was pressed again since the last time you checked.
|
||||
* @param button the button to query the request
|
||||
*/
|
||||
//% help=input/button/was-pressed weight=78
|
||||
//% help=input/button/was-pressed
|
||||
//% block="%button|was pressed"
|
||||
//% blockId=buttonWasPressed
|
||||
//% parts="buttonpair" blockGap=8
|
||||
//% blockNamespace=input advanced=true
|
||||
//% group="Brick buttons"
|
||||
//% button.fieldEditor="gridpicker"
|
||||
//% button.fieldOptions.width=220
|
||||
//% button.fieldOptions.columns=3
|
||||
//% parts="brick"
|
||||
//% blockNamespace=input
|
||||
//% weight=80 blockGap=8
|
||||
//% group="Brick"
|
||||
wasPressed() {
|
||||
const r = this._wasPressed
|
||||
this._wasPressed = false
|
||||
@ -118,19 +112,17 @@ namespace input {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a button or sensor is clicked, double clicked, etc...
|
||||
* Do something when a button or sensor is clicked, up or down.
|
||||
* @param button the button that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
*/
|
||||
//% help=input/button/on-event weight=99 blockGap=8
|
||||
//% help=input/button/on-event
|
||||
//% blockId=buttonEvent block="on %button|%event"
|
||||
//% parts="buttonpair"
|
||||
//% parts="brick"
|
||||
//% blockNamespace=input
|
||||
//% group="Brick buttons"
|
||||
//% button.fieldEditor="gridpicker"
|
||||
//% button.fieldOptions.width=220
|
||||
//% button.fieldOptions.columns=3
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Brick"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
control.onEvent(this._id, ev, body)
|
||||
}
|
||||
@ -167,7 +159,7 @@ namespace input {
|
||||
if (curr & DAL.BUTTON_ID_ESCAPE)
|
||||
control.reset()
|
||||
for (let b of buttons)
|
||||
b.update(!!(curr & b.mask))
|
||||
b._update(!!(curr & b.mask))
|
||||
})
|
||||
control.dmesg("runtime started, " + control.deviceFirmwareVersion())
|
||||
}
|
||||
@ -184,35 +176,36 @@ namespace input {
|
||||
|
||||
initBtns() // always ON as it handles ESCAPE button
|
||||
|
||||
|
||||
/**
|
||||
* Left button.
|
||||
* Enter button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button left" weight=95 fixedInstance
|
||||
//% whenUsed block="brick button enter" weight=95 fixedInstance
|
||||
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
|
||||
|
||||
/**
|
||||
* Left button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="brick button left" weight=95 fixedInstance
|
||||
export const buttonLeft: Button = new DevButton(DAL.BUTTON_ID_LEFT)
|
||||
|
||||
/**
|
||||
* Right button.
|
||||
* Right button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button right" weight=94 fixedInstance
|
||||
//% whenUsed block="brick button right" weight=94 fixedInstance
|
||||
export const buttonRight: Button = new DevButton(DAL.BUTTON_ID_RIGHT)
|
||||
|
||||
/**
|
||||
* Up button.
|
||||
* Up button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button up" weight=95 fixedInstance
|
||||
//% whenUsed block="brick button up" weight=95 fixedInstance
|
||||
export const buttonUp: Button = new DevButton(DAL.BUTTON_ID_UP)
|
||||
|
||||
/**
|
||||
* Down button.
|
||||
* Down button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button down" weight=95 fixedInstance
|
||||
//% whenUsed block="brick button down" weight=95 fixedInstance
|
||||
export const buttonDown: Button = new DevButton(DAL.BUTTON_ID_DOWN)
|
||||
|
||||
/**
|
||||
* Enter button.
|
||||
*/
|
||||
//% whenUsed block="button enter" weight=95 fixedInstance
|
||||
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
|
||||
}
|
||||
|
||||
|
||||
@ -241,8 +234,8 @@ namespace output {
|
||||
* @param pattern the lights pattern to use.
|
||||
*/
|
||||
//% blockId=setLights block="set status light %pattern=led_pattern"
|
||||
//% weight=100 group="Lights"
|
||||
export function setLights(pattern: number): void {
|
||||
//% weight=100 group="Brick"
|
||||
export function setStatusLight(pattern: number): void {
|
||||
if (currPattern === pattern)
|
||||
return
|
||||
currPattern = pattern
|
||||
@ -259,7 +252,7 @@ namespace output {
|
||||
//% blockId=led_pattern block="%pattern"
|
||||
//% shim=TD_ID colorSecondary="#6e9a36"
|
||||
//% blockHidden=true useEnumVal=1 pattern.fieldOptions.decompileLiterals=1
|
||||
export function getPattern(pattern: LightsPattern): number {
|
||||
export function pattern(pattern: LightsPattern): number {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
@ -9,21 +9,30 @@ const enum ColorSensorMode {
|
||||
}
|
||||
|
||||
const enum ColorSensorColor {
|
||||
//% block="none"
|
||||
None,
|
||||
//% block="black"
|
||||
Black,
|
||||
//% block="blue"
|
||||
Blue,
|
||||
//% block="green"
|
||||
Green,
|
||||
//% block="yellow"
|
||||
Yellow,
|
||||
//% block="red"
|
||||
Red,
|
||||
//% block="white"
|
||||
White,
|
||||
//% block="brown"
|
||||
Brown,
|
||||
}
|
||||
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class ColorSensor extends internal.UartSensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
@ -34,22 +43,93 @@ namespace input {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
getAmbientLight() {
|
||||
_query() {
|
||||
if (this.mode == ColorSensorMode.Color)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
return 0
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
control.raiseEvent(this._id, curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the given color is detected
|
||||
* @param color the color to dtect
|
||||
* @param handler the code to run when detected
|
||||
*/
|
||||
//% help=input/color/on-color-detected
|
||||
//% block="on %sensor|detected %color"
|
||||
//% blockId=colorOnColorDetected
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
||||
control.onEvent(this._id, <number>color, handler);
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
if (this.color() == color)
|
||||
control.runInBackground(handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ambient light value from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
*/
|
||||
//% help=input/color/ambient-light
|
||||
//% block="%color| ambient light"
|
||||
//% blockId=colorGetAmbient
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
ambientLight() {
|
||||
this.setMode(ColorSensorMode.Ambient)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
getReflectedLight() {
|
||||
/**
|
||||
* Get current reflected light value from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
*/
|
||||
//% help=input/color/refelected-light
|
||||
//% block="%color| reflected light"
|
||||
//% blockId=colorGetReflected
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=64 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
reflectedLight(): number {
|
||||
this.setMode(ColorSensorMode.Reflect)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
getColor(): ColorSensorColor {
|
||||
/**
|
||||
* Get the current color from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
*/
|
||||
//% help=input/color/color
|
||||
//% block="%color| color"
|
||||
//% blockId=colorGetColor
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=66 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
color(): ColorSensorColor {
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const color: ColorSensor = new ColorSensor()
|
||||
//% whenUsed block="color sensor 3" weight=95 fixedInstance
|
||||
export const color3: ColorSensor = new ColorSensor(3)
|
||||
|
||||
//% whenUsed block="color sensor 1" weight=95 fixedInstance
|
||||
export const color1: ColorSensor = new ColorSensor(1)
|
||||
|
||||
//% whenUsed block="color sensor 2" weight=95 fixedInstance
|
||||
export const color2: ColorSensor = new ColorSensor(2)
|
||||
|
||||
//% whenUsed block="color sensor 4" weight=95 fixedInstance
|
||||
export const color4: ColorSensor = new ColorSensor(4)
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ const enum GyroSensorMode {
|
||||
}
|
||||
|
||||
namespace input {
|
||||
//% fixedInstances
|
||||
export class GyroSensor extends internal.UartSensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
@ -18,17 +19,48 @@ namespace input {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
getAngle() {
|
||||
/**
|
||||
* Get the current angle from the gyroscope.
|
||||
* @param sensor the gyroscope to query the request
|
||||
*/
|
||||
//% help=input/gyro/angle
|
||||
//% block="%sensor|angle"
|
||||
//% blockId=gyroGetAngle
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
angle() {
|
||||
this.setMode(GyroSensorMode.Angle)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
}
|
||||
|
||||
getRate() {
|
||||
/**
|
||||
* Get the current rotation rate from the gyroscope.
|
||||
* @param sensor the gyroscope to query the request
|
||||
*/
|
||||
//% help=input/gyro/rate
|
||||
//% block="%sensor|rotation rate"
|
||||
//% blockId=gyroGetRate
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
rate() {
|
||||
this.setMode(GyroSensorMode.Rate)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const gyro: GyroSensor = new GyroSensor()
|
||||
//% fixedInstance whenUsed block="gyro sensor 2"
|
||||
export const gyro2: GyroSensor = new GyroSensor(2)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro sensor 1"
|
||||
export const gyro1: GyroSensor = new GyroSensor(1)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro sensor 3"
|
||||
export const gyro3: GyroSensor = new GyroSensor(3)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro sensor 4"
|
||||
export const gyro4: GyroSensor = new GyroSensor(4)
|
||||
}
|
||||
|
@ -27,30 +27,27 @@ namespace input.internal {
|
||||
let analogMM: MMap
|
||||
let uartMM: MMap
|
||||
let devcon: Buffer
|
||||
let sensors: SensorInfo[]
|
||||
let autoSensors: Sensor[]
|
||||
let sensorInfos: SensorInfo[]
|
||||
|
||||
class SensorInfo {
|
||||
port: number
|
||||
sensor: Sensor
|
||||
sensors: Sensor[]
|
||||
connType: number
|
||||
devType: number
|
||||
manual: boolean
|
||||
|
||||
constructor(p: number) {
|
||||
this.port = p
|
||||
this.connType = DAL.CONN_NONE
|
||||
this.devType = DAL.DEVICE_TYPE_NONE
|
||||
this.sensor = null
|
||||
this.manual = false
|
||||
this.sensors = []
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (sensors) return
|
||||
sensors = []
|
||||
for (let i = 0; i < DAL.NUM_INPUTS; ++i) sensors.push(new SensorInfo(i))
|
||||
autoSensors = []
|
||||
if (sensorInfos) return
|
||||
sensorInfos = []
|
||||
for (let i = 0; i < DAL.NUM_INPUTS; ++i) sensorInfos.push(new SensorInfo(i))
|
||||
devcon = output.createBuffer(DevConOff.Size)
|
||||
|
||||
analogMM = control.mmap("/dev/lms_analog", AnalogOff.Size, 0)
|
||||
@ -64,7 +61,7 @@ namespace input.internal {
|
||||
loops.pause(500)
|
||||
})
|
||||
|
||||
for (let info_ of sensors) {
|
||||
for (let info_ of sensorInfos) {
|
||||
let info = info_
|
||||
unsafePollForChanges(50, () => {
|
||||
if (info.sensor) return info.sensor._query()
|
||||
@ -90,7 +87,7 @@ namespace input.internal {
|
||||
let conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
|
||||
let numChanged = 0
|
||||
|
||||
for (let info of sensors) {
|
||||
for (let info of sensorInfos) {
|
||||
let newConn = conns[info.port]
|
||||
if (newConn == info.connType)
|
||||
continue
|
||||
@ -117,77 +114,44 @@ namespace input.internal {
|
||||
if (numChanged == 0)
|
||||
return
|
||||
|
||||
let autos = sensors.filter(s => !s.manual)
|
||||
|
||||
// first free up disconnected sensors
|
||||
for (let info of autos) {
|
||||
if (info.sensor && info.devType == DAL.DEVICE_TYPE_NONE)
|
||||
info.sensor._setPort(0)
|
||||
}
|
||||
|
||||
for (let info of autos) {
|
||||
if (!info.sensor && info.devType != DAL.DEVICE_TYPE_NONE) {
|
||||
let found = false
|
||||
for (let s of autoSensors) {
|
||||
if (s.getPort() == 0 && s._deviceType() == info.devType) {
|
||||
s._setPort(info.port + 1)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
for (let si of sensorInfos) {
|
||||
if (si.sensor && si.sensor._deviceType() != si.devType) {
|
||||
si.sensor = null
|
||||
}
|
||||
if (si.devType != DAL.DEVICE_TYPE_NONE) {
|
||||
// TODO figure out compiler problem when '|| null' is added here!
|
||||
si.sensor = si.sensors.filter(s => s._deviceType() == si.devType)[0]
|
||||
if (si.sensor == null) {
|
||||
control.dmesg(`sensor not found for type=${si.devType} at ${si.port}`)
|
||||
} else {
|
||||
control.dmesg(`sensor connected type=${si.devType} at ${si.port}`)
|
||||
si.sensor._activated()
|
||||
}
|
||||
if (!found)
|
||||
control.dmesg(`sensor not found for type=${info.devType} at ${info.port}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Sensor extends control.Component {
|
||||
protected port: number
|
||||
protected port: number // this is 0-based
|
||||
|
||||
constructor() {
|
||||
constructor(port_: number) {
|
||||
super()
|
||||
if (!(1 <= port_ && port_ <= DAL.NUM_INPUTS))
|
||||
control.panic(120)
|
||||
this.port = port_ - 1
|
||||
init()
|
||||
this.port = -1
|
||||
let tp = this._deviceType()
|
||||
if (autoSensors.filter(s => s._deviceType() == tp).length == 0) {
|
||||
autoSensors.push(this)
|
||||
}
|
||||
sensorInfos[this.port].sensors.push(this)
|
||||
}
|
||||
|
||||
// 0 - disable, 1-4 port number
|
||||
_setPort(port: number, manual = false) {
|
||||
port = Math.clamp(0, 4, port | 0) - 1;
|
||||
if (port == this.port) return
|
||||
this.port = port
|
||||
control.dmesg(`sensor set port ${port} on devtype=${this._deviceType()}`)
|
||||
for (let i = 0; i < sensors.length; ++i) {
|
||||
if (i != this.port && sensors[i].sensor == this) {
|
||||
sensors[i].sensor = null
|
||||
sensors[i].manual = false
|
||||
}
|
||||
}
|
||||
if (this.port >= 0) {
|
||||
let prev = sensors[this.port].sensor
|
||||
if (prev && prev != this)
|
||||
prev._setPort(0)
|
||||
sensors[this.port].sensor = this
|
||||
sensors[this.port].manual = manual
|
||||
}
|
||||
this._portUpdated()
|
||||
}
|
||||
|
||||
protected _portUpdated() { }
|
||||
|
||||
setPort(port: number) {
|
||||
this._setPort(port, true)
|
||||
}
|
||||
_activated() { }
|
||||
|
||||
// 1-based
|
||||
getPort() {
|
||||
return this.port + 1
|
||||
}
|
||||
|
||||
isManual() {
|
||||
return this.port >= 0 && sensors[this.port].manual
|
||||
isActive() {
|
||||
return sensorInfos[this.port].sensor == this
|
||||
}
|
||||
|
||||
_query() {
|
||||
@ -203,12 +167,12 @@ namespace input.internal {
|
||||
}
|
||||
|
||||
export class AnalogSensor extends Sensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_readPin6() {
|
||||
if (this.port < 0) return 0
|
||||
if (!this.isActive()) return 0
|
||||
return analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.InPin6 + 2 * this.port)
|
||||
}
|
||||
}
|
||||
@ -216,32 +180,26 @@ namespace input.internal {
|
||||
|
||||
|
||||
export class UartSensor extends Sensor {
|
||||
protected mode: number
|
||||
protected realmode: number
|
||||
protected mode: number // the mode user asked for
|
||||
protected realmode: number // the mode the hardware is in
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.mode = 0
|
||||
this.realmode = -1
|
||||
}
|
||||
|
||||
protected _portUpdated() {
|
||||
this.realmode = -1
|
||||
if (this.port >= 0) {
|
||||
if (this.isManual()) {
|
||||
uartReset(this.port)
|
||||
} else {
|
||||
this.realmode = 0
|
||||
}
|
||||
this._setMode(this.mode)
|
||||
}
|
||||
_activated() {
|
||||
this.realmode = 0
|
||||
// uartReset(this.port) // TODO is it ever needed?
|
||||
this._setMode(this.mode)
|
||||
}
|
||||
|
||||
protected _setMode(m: number) {
|
||||
//control.dmesg(`_setMode p=${this.port} m: ${this.realmode} -> ${m}`)
|
||||
let v = m | 0
|
||||
this.mode = v
|
||||
if (this.port < 0) return
|
||||
if (!this.isActive()) return
|
||||
if (this.realmode != this.mode) {
|
||||
this.realmode = v
|
||||
setUartMode(this.port, v)
|
||||
@ -249,10 +207,12 @@ namespace input.internal {
|
||||
}
|
||||
|
||||
getBytes(): Buffer {
|
||||
return getUartBytes(this.port)
|
||||
return getUartBytes(this.isActive() ? this.port : -1)
|
||||
}
|
||||
|
||||
getNumber(fmt: NumberFormat, off: number) {
|
||||
if (!this.isActive())
|
||||
return 0
|
||||
return getUartNumber(fmt, off, this.port)
|
||||
}
|
||||
}
|
||||
|
247
libs/core/ir.ts
@ -40,41 +40,130 @@ namespace input {
|
||||
}
|
||||
}
|
||||
|
||||
export class IrSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel
|
||||
private buttons: Button[];
|
||||
let buttons: RemoteInfraredBeaconButton[]
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.channel = IrRemoteChannel.Ch0
|
||||
this.buttons = []
|
||||
// otherwise button events won't work
|
||||
this.mode = IrSensorMode.RemoteControl
|
||||
function create(ir: InfraredSensor) {
|
||||
// it's created by referencing it
|
||||
}
|
||||
|
||||
export function irButton(id: IrRemoteButton): RemoteInfraredBeaconButton {
|
||||
if (buttons == null) {
|
||||
buttons = []
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
this.buttons.push(new Button())
|
||||
buttons.push(new RemoteInfraredBeaconButton(new Button()))
|
||||
}
|
||||
|
||||
// make sure sensors are up
|
||||
create(infraredSensor1)
|
||||
create(infraredSensor2)
|
||||
create(infraredSensor3)
|
||||
create(infraredSensor4)
|
||||
}
|
||||
|
||||
button(id: IrRemoteButton) {
|
||||
let num = -1
|
||||
while (id) {
|
||||
id >>= 1;
|
||||
num++;
|
||||
}
|
||||
num = Math.clamp(0, this.buttons.length - 1, num)
|
||||
return this.buttons[num]
|
||||
let num = -1
|
||||
while (id) {
|
||||
id >>= 1;
|
||||
num++;
|
||||
}
|
||||
num = Math.clamp(0, buttons.length - 1, num)
|
||||
return buttons[num]
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class RemoteInfraredBeaconButton extends control.Component {
|
||||
private button: Button;
|
||||
constructor(button: Button) {
|
||||
super();
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
_update(curr: boolean) {
|
||||
this.button._update(curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a remote button is currently pressed or not.
|
||||
* @param button the remote button to query the request
|
||||
*/
|
||||
//% help=input/remote-infrared-beacon/is-pressed
|
||||
//% block="%button|is pressed"
|
||||
//% blockId=remoteButtonIsPressed
|
||||
//% parts="remote"
|
||||
//% blockNamespace=input
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
isPressed() {
|
||||
return this.button.isPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the remote button was pressed again since the last time you checked.
|
||||
* @param button the remote button to query the request
|
||||
*/
|
||||
//% help=input/remote-infrared-beacon/was-pressed
|
||||
//% block="%button|was pressed"
|
||||
//% blockId=remotebuttonWasPressed
|
||||
//% parts="remote"
|
||||
//% blockNamespace=input
|
||||
//% weight=80 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
wasPressed() {
|
||||
return this.button.wasPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a button or sensor is clicked, up or down
|
||||
* @param button the button that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
*/
|
||||
//% help=input/remote-infrared-beacon/on-event
|
||||
//% blockId=remotebuttonEvent block="on %button|%event"
|
||||
//% parts="remote"
|
||||
//% blockNamespace=input
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
this.button.onEvent(ev, body);
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class InfraredSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel;
|
||||
private proximityThreshold: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.channel = IrRemoteChannel.Ch0
|
||||
this.proximityThreshold = 10;
|
||||
irButton(0) // make sure buttons array is initalized
|
||||
|
||||
// and set the mode, as otherwise button events won't work
|
||||
this.mode = IrSensorMode.RemoteControl;
|
||||
}
|
||||
|
||||
_query() {
|
||||
if (this.mode == IrSensorMode.RemoteControl)
|
||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel))
|
||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel));
|
||||
else if (this.mode == IrSensorMode.Proximity) {
|
||||
const d = this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
return d < this.proximityThreshold ? PromixityEvent.ObjectNear
|
||||
: d > this.proximityThreshold + 5 ? PromixityEvent.ObjectDetected
|
||||
: 0;
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
for (let i = 0; i < this.buttons.length; ++i) {
|
||||
let v = !!(curr & (1 << i))
|
||||
this.buttons[i].update(v)
|
||||
if (this.mode == IrSensorMode.RemoteControl) {
|
||||
for (let i = 0; i < buttons.length; ++i) {
|
||||
let v = !!(curr & (1 << i))
|
||||
buttons[i]._update(v)
|
||||
}
|
||||
} else {
|
||||
if (curr)
|
||||
control.raiseEvent(this._id, curr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,59 +174,113 @@ namespace input {
|
||||
setRemoteChannel(c: IrRemoteChannel) {
|
||||
c = Math.clamp(0, 3, c | 0)
|
||||
this.channel = c
|
||||
this.setMode(IrSensorMode.RemoteControl)
|
||||
this._setMode(IrSensorMode.RemoteControl)
|
||||
}
|
||||
|
||||
setMode(m: IrSensorMode) {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
getDistance() {
|
||||
this.setMode(IrSensorMode.Proximity)
|
||||
/**
|
||||
* Registers code to run when an object is getting near.
|
||||
* @param handler the code to run when detected
|
||||
*/
|
||||
//% help=input/infrared/on-object-near
|
||||
//% block="on %sensor|object near"
|
||||
//% blockId=infraredOnObjectNear
|
||||
//% parts="infraredsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
onObjectNear(handler: () => void) {
|
||||
control.onEvent(this._id, PromixityEvent.ObjectNear, handler);
|
||||
if (this.proximity() == PromixityEvent.ObjectNear)
|
||||
control.runInBackground(handler);
|
||||
}
|
||||
|
||||
setObjectNearThreshold(distance: number) {
|
||||
this.proximityThreshold = Math.max(1, Math.min(95, distance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the promixity measured by the infrared sensor, from ``0`` (close) to ``100`` (far)
|
||||
* @param ir the infrared sensor
|
||||
*/
|
||||
//% help=input/infrared/proximity
|
||||
//% block="%infrared|proximity"
|
||||
//% blockId=infraredGetProximity
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
proximity() {
|
||||
this._setMode(IrSensorMode.Proximity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
getRemoteCommand() {
|
||||
this.setMode(IrSensorMode.RemoteControl)
|
||||
/**
|
||||
* Get the remote commandreceived the infrared sensor.
|
||||
* @param ir the infrared sensor
|
||||
*/
|
||||
//% help=input/infrared/remote-command
|
||||
//% block="%infrared|remote command"
|
||||
//% blockId=infraredGetRemoteCommand
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
remoteCommand() {
|
||||
this._setMode(IrSensorMode.RemoteControl)
|
||||
return this.getNumber(NumberFormat.UInt8LE, this.channel)
|
||||
}
|
||||
|
||||
// TODO
|
||||
getDirectionAndDistance() {
|
||||
this.setMode(IrSensorMode.Seek)
|
||||
this._setMode(IrSensorMode.Seek)
|
||||
return this.getNumber(NumberFormat.UInt16LE, this.channel * 2)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const ir: IrSensor = new IrSensor()
|
||||
//% fixedInstance whenUsed block="infrared sensor 1"
|
||||
export const infraredSensor1: InfraredSensor = new InfraredSensor(1)
|
||||
|
||||
/**
|
||||
* Remote top-left button.
|
||||
*/
|
||||
//% whenUsed block="remote top-left" weight=95 fixedInstance
|
||||
export const remoteTopLeft = ir.button(IrRemoteButton.TopLeft)
|
||||
//% fixedInstance whenUsed block="infrared sensor 2"
|
||||
export const infraredSensor2: InfraredSensor = new InfraredSensor(2)
|
||||
|
||||
/**
|
||||
* Remote top-right button.
|
||||
*/
|
||||
//% whenUsed block="remote top-right" weight=95 fixedInstance
|
||||
export const remoteTopRight = ir.button(IrRemoteButton.TopRight)
|
||||
//% fixedInstance whenUsed block="infrared sensor 3"
|
||||
export const infraredSensor3: InfraredSensor = new InfraredSensor(3)
|
||||
|
||||
/**
|
||||
* Remote bottom-left button.
|
||||
*/
|
||||
//% whenUsed block="remote bottom-left" weight=95 fixedInstance
|
||||
export const remoteBottomLeft = ir.button(IrRemoteButton.BottomLeft)
|
||||
//% fixedInstance whenUsed block="infrared sensor 4"
|
||||
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
||||
|
||||
/**
|
||||
* Remote bottom-right button.
|
||||
*/
|
||||
//% whenUsed block="remote bottom-right" weight=95 fixedInstance
|
||||
export const remoteBottomRight = ir.button(IrRemoteButton.BottomRight)
|
||||
|
||||
/**
|
||||
* Remote beacon (center) button.
|
||||
*/
|
||||
//% whenUsed block="remote center" weight=95 fixedInstance
|
||||
export const remoteCenter = ir.button(IrRemoteButton.CenterBeacon)
|
||||
//% whenUsed block="remote button center" weight=95 fixedInstance
|
||||
export const remoteButtonCenter = irButton(IrRemoteButton.CenterBeacon)
|
||||
|
||||
/**
|
||||
* Remote top-left button.
|
||||
*/
|
||||
//% whenUsed block="remote button top-left" weight=95 fixedInstance
|
||||
export const remoteButtonTopLeft = irButton(IrRemoteButton.TopLeft)
|
||||
|
||||
/**
|
||||
* Remote top-right button.
|
||||
*/
|
||||
//% whenUsed block="remote button top-right" weight=95 fixedInstance
|
||||
export const remoteButtonTopRight = irButton(IrRemoteButton.TopRight)
|
||||
|
||||
/**
|
||||
* Remote bottom-left button.
|
||||
*/
|
||||
//% whenUsed block="remote button bottom-left" weight=95 fixedInstance
|
||||
export const remoteButtonBottomLeft = irButton(IrRemoteButton.BottomLeft)
|
||||
|
||||
/**
|
||||
* Remote bottom-right button.
|
||||
*/
|
||||
//% whenUsed block="remote button bottom-right" weight=95 fixedInstance
|
||||
export const remoteButtonBottomRight = irButton(IrRemoteButton.BottomRight)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
//% color="#B4009E" weight=98 icon="\uf192"
|
||||
//% groups='["Brick", "Touch Sensor", "Color Sensor", "Ultrasonic Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||
namespace input {
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
enum Output {
|
||||
//% block="A"
|
||||
A = 0x01,
|
||||
//% block="B"
|
||||
B = 0x02,
|
||||
//% block="C"
|
||||
C = 0x04,
|
||||
//% block="D"
|
||||
D = 0x08,
|
||||
//% block="All"
|
||||
ALL = 0x0f
|
||||
}
|
||||
|
||||
@ -15,7 +20,6 @@ enum OutputType {
|
||||
namespace output {
|
||||
let pwmMM: MMap
|
||||
let motorMM: MMap
|
||||
let currentSpeed: number[] = []
|
||||
|
||||
const enum MotorDataOff {
|
||||
TachoCounts = 0, // int32
|
||||
@ -31,13 +35,7 @@ namespace output {
|
||||
if (!pwmMM) control.fail("no PWM file")
|
||||
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
||||
|
||||
stop(Output.ALL)
|
||||
|
||||
currentSpeed[Output.A] = -1;
|
||||
currentSpeed[Output.B] = -1;
|
||||
currentSpeed[Output.C] = -1;
|
||||
currentSpeed[Output.D] = -1;
|
||||
currentSpeed[Output.ALL] = -1;
|
||||
resetMotors()
|
||||
|
||||
let buf = output.createBuffer(1)
|
||||
buf[0] = DAL.opProgramStart
|
||||
@ -55,69 +53,173 @@ namespace output {
|
||||
}
|
||||
|
||||
function mkCmd(out: Output, cmd: number, addSize: number) {
|
||||
let b = createBuffer(2 + addSize)
|
||||
const b = createBuffer(2 + addSize)
|
||||
b.setNumber(NumberFormat.UInt8LE, 0, cmd)
|
||||
b.setNumber(NumberFormat.UInt8LE, 1, out)
|
||||
return b
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a motor on for a specified number of milliseconds.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param ms the number of milliseconds to turn the motor on, eg: 500
|
||||
* @param useBrake whether or not to use the brake, defaults to false
|
||||
*/
|
||||
//% blockId=output_turn block="turn motor %out| on for %ms|milliseconds"
|
||||
//% weight=100 group="Motors"
|
||||
export function turn(out: Output, ms: number, useBrake = false) {
|
||||
// TODO: use current power / speed configuration
|
||||
output.step(out, {
|
||||
speed: 100,
|
||||
step1: 0,
|
||||
step2: ms,
|
||||
step3: 0,
|
||||
useSteps: false,
|
||||
useBrake: useBrake
|
||||
})
|
||||
function resetMotors() {
|
||||
reset(Output.ALL)
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn motor off.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* Stops all motors
|
||||
*/
|
||||
//% blockId=output_stop block="turn motor %out|off"
|
||||
//% weight=90 group="Motors"
|
||||
export function stop(out: Output, useBrake = false) {
|
||||
let b = mkCmd(out, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, useBrake ? 1 : 0)
|
||||
//% blockId=motorStopAll block="stop all motors"
|
||||
//% weight=10 group="Motors" blockGap=8
|
||||
export function stopAllMotors() {
|
||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn motor on.
|
||||
* @param out the output connection that the motor is connected to
|
||||
*/
|
||||
//% blockId=output_start block="turn motor %out|on"
|
||||
//% weight=95 group="Motors"
|
||||
export function start(out: Output) {
|
||||
if (currentSpeed[out] == -1) setSpeed(out, 50)
|
||||
let b = mkCmd(out, DAL.opOutputStart, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
//% fixedInstances
|
||||
export class Motor extends control.Component {
|
||||
private port: Output;
|
||||
private large: boolean;
|
||||
private brake: boolean;
|
||||
|
||||
export function reset(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
constructor(port: Output, large: boolean) {
|
||||
super();
|
||||
this.port = port;
|
||||
this.large = large;
|
||||
this.brake = false;
|
||||
}
|
||||
|
||||
export function clearCount(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputClearCount, 0)
|
||||
writePWM(b)
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (out & (1 << i)) {
|
||||
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
||||
/**
|
||||
* Power on or off the motor.
|
||||
* @param motor the motor to turn on
|
||||
* @param power the motor power level from ``-100`` to ``100``, eg: 50
|
||||
*/
|
||||
//% blockId=outputMotorOn block="%motor|%onOrOff"
|
||||
//% onOrOff.fieldEditor=toggleonoff
|
||||
//% weight=99 group="Motors" blockGap=8
|
||||
on(onOrOff: boolean = true) {
|
||||
if (onOrOff) {
|
||||
const b = mkCmd(this.port, DAL.opOutputStart, 0)
|
||||
writePWM(b);
|
||||
} else {
|
||||
const b = mkCmd(this.port, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, this.brake ? 1 : 0)
|
||||
writePWM(b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the motor power level from ``-100`` to ``100``.
|
||||
* @param motor the output connection that the motor is connected to
|
||||
* @param power the desired speed to use. eg: 50
|
||||
*/
|
||||
//% blockId=motorSetPower block="%motor|set power to %speed"
|
||||
//% weight=62 group="Motors" blockGap=8
|
||||
//% speed.min=-100 speed.max=100
|
||||
setPower(power: number) {
|
||||
const b = mkCmd(this.port, DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, power))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the automatic brake on or off when the motor is off
|
||||
* @param brake a value indicating if the motor should break when off
|
||||
*/
|
||||
//% blockId=outputMotorSetBrakeMode block="%motor|set brake %brake"
|
||||
//% brake.fieldEditor=toggleonoff
|
||||
//% weight=60 group="Motors" blockGap=8
|
||||
setBrake(brake: boolean) {
|
||||
this.brake = brake;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the motor polarity
|
||||
*/
|
||||
//% blockId=motorSetReversed block="%motor|set reversed %reversed"
|
||||
//% reversed.fieldEditor=toggleonoff
|
||||
//% weight=59 group="Motors"
|
||||
setReversed(reversed: boolean) {
|
||||
const b = mkCmd(this.port, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, reversed ? -1 : 1);
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor actual speed.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorSpeed block="%motor|speed"
|
||||
//% weight=50 group="Motors" blockGap=8
|
||||
speed(): number {
|
||||
return getMotorData(this.port).actualSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor step count.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorCount block="%motor|count"
|
||||
//% weight=49 group="Motors" blockGap=8
|
||||
count(): number {
|
||||
return getMotorData(this.port).count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor tacho count.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorTachoCount block="%motor|tacho count"
|
||||
//% weight=48 group="Motors"
|
||||
tachoCount(): number {
|
||||
return getMotorData(this.port).tachoCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the motor count
|
||||
*/
|
||||
clearCount() {
|
||||
const b = mkCmd(this.port, DAL.opOutputClearCount, 0)
|
||||
writePWM(b)
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (this.port & (1 << i)) {
|
||||
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the motor.
|
||||
*/
|
||||
reset() {
|
||||
reset(this.port);
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="large motor A"
|
||||
export const largeMotorA = new Motor(Output.A, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large motor B"
|
||||
export const largeMotorB = new Motor(Output.B, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large motor C"
|
||||
export const largeMotorC = new Motor(Output.C, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large motor D"
|
||||
export const largeMotorD = new Motor(Output.D, true);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor A"
|
||||
export const mediumMotorA = new Motor(Output.A, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor B"
|
||||
export const mediumMotorB = new Motor(Output.B, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor C"
|
||||
export const mediumMotorC = new Motor(Output.C, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor D"
|
||||
export const mediumMotorD = new Motor(Output.D, false);
|
||||
|
||||
function reset(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
function outOffset(out: Output) {
|
||||
@ -128,14 +230,14 @@ namespace output {
|
||||
return 0
|
||||
}
|
||||
|
||||
export interface MotorData {
|
||||
interface MotorData {
|
||||
actualSpeed: number; // -100..+100
|
||||
tachoCount: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
// only a single output at a time
|
||||
export function getMotorData(out: Output): MotorData {
|
||||
function getMotorData(out: Output): MotorData {
|
||||
let buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
||||
return {
|
||||
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
||||
@ -144,52 +246,7 @@ namespace output {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get motor speed.
|
||||
* @param out the output connection that the motor is connected to
|
||||
*/
|
||||
//% blockId=output_getCurrentSpeed block="motor %out|speed"
|
||||
//% weight=70 group="Motors"
|
||||
export function getCurrentSpeed(out: Output) {
|
||||
return getMotorData(out).actualSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set motor speed.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param speed the desired speed to use. eg: 100
|
||||
*/
|
||||
//% blockId=output_setSpeed block="set motor %out| speed to %speed"
|
||||
//% weight=81 group="Motors"
|
||||
//% speed.min=-100 speed.max=100
|
||||
export function setSpeed(out: Output, speed: number) {
|
||||
currentSpeed[out] = speed;
|
||||
let b = mkCmd(out, DAL.opOutputSpeed, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, speed))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set motor power.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param power the desired power to use. eg: 100
|
||||
*/
|
||||
//% blockId=output_setPower block="set motor %out| power to %power"
|
||||
//% weight=80 group="Motors"
|
||||
//% power.min=-100 power.max=100
|
||||
export function setPower(out: Output, power: number) {
|
||||
let b = mkCmd(out, DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, power))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export function setPolarity(out: Output, polarity: number) {
|
||||
let b = mkCmd(out, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-1, 1, polarity))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export interface StepOptions {
|
||||
interface StepOptions {
|
||||
power?: number;
|
||||
speed?: number; // either speed or power has to be present
|
||||
step1: number;
|
||||
@ -199,7 +256,7 @@ namespace output {
|
||||
useBrake?: boolean;
|
||||
}
|
||||
|
||||
export function step(out: Output, opts: StepOptions) {
|
||||
function step(out: Output, opts: StepOptions) {
|
||||
let op = opts.useSteps ? DAL.opOutputStepSpeed : DAL.opOutputTimeSpeed
|
||||
let speed = opts.speed
|
||||
if (speed == null) {
|
||||
|
@ -78,13 +78,21 @@ namespace screen {
|
||||
}
|
||||
}
|
||||
|
||||
export function setPixel(x: number, y: number, mode = Draw.Normal) {
|
||||
/**
|
||||
* Sets a pixel on or off
|
||||
* @param on a value indicating if the pixel should be on or off
|
||||
* @param x the starting position's x coordinate, eg: 0
|
||||
* @param y the starting position's x coordinate, eg: 0
|
||||
*/
|
||||
//% blockId=screen_setpixel block="set pixel %on| at x: %x| y: %y"
|
||||
//% weight=98 group="Brick" blockNamespace=output
|
||||
//% x.min=0 x.max=178 y.min=0 y.max=128 on.fieldEditor=toggleonoff
|
||||
export function setPixel(on: boolean, x: number, y: number) {
|
||||
x |= 0
|
||||
y |= 0
|
||||
if (0 <= x && x < DAL.LCD_WIDTH && 0 <= y && y < DAL.LCD_HEIGHT)
|
||||
_setPixel(x, y, mode)
|
||||
_setPixel(x, y, on ? Draw.Normal : Draw.Clear)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show text on the screen.
|
||||
@ -92,10 +100,10 @@ namespace screen {
|
||||
* @param x the starting position's x coordinate, eg: 0
|
||||
* @param y the starting position's x coordinate, eg: 0
|
||||
*/
|
||||
//% blockId=screen_drawText block="print %text| at x: %x| y: %y"
|
||||
//% weight=99 group="Screen" blockNamespace=output inlineInputMode="inline"
|
||||
//% blockId=screen_print block="print %text| at x: %x| y: %y"
|
||||
//% weight=99 group="Brick" blockNamespace=output inlineInputMode="inline"
|
||||
//% x.min=0 x.max=178 y.min=0 y.max=128
|
||||
export function drawText(text: string, x: number, y: number, mode = Draw.Normal) {
|
||||
export function print(text: string, x: number, y: number, mode = Draw.Normal) {
|
||||
x |= 0
|
||||
y |= 0
|
||||
if (!currFont) currFont = defaultFont()
|
||||
|
@ -1,8 +1,8 @@
|
||||
screen.clear()
|
||||
screen.drawText("PXT!", 10, 30, Draw.Quad)
|
||||
screen.print("PXT!", 10, 30, Draw.Quad)
|
||||
|
||||
screen.drawRect(40, 40, 20, 10, Draw.Fill)
|
||||
output.setLights(LightsPattern.Orange)
|
||||
output.setStatusLight(LightsPattern.Orange)
|
||||
|
||||
screen.drawIcon(100, 50, screen.doubleIcon(screen.heart), Draw.Double | Draw.Transparent)
|
||||
|
||||
@ -12,37 +12,37 @@ input.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
||||
|
||||
input.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||
output.setLights(LightsPattern.Red)
|
||||
output.setStatusLight(LightsPattern.Red)
|
||||
screen.setFont(screen.microbitFont())
|
||||
})
|
||||
|
||||
input.buttonRight.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText("Right!", 10, 60)
|
||||
screen.print("Right!", 10, 60)
|
||||
})
|
||||
|
||||
input.buttonDown.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText("Down! ", 10, 60)
|
||||
screen.print("Down! ", 10, 60)
|
||||
})
|
||||
|
||||
input.buttonUp.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText("Up! ", 10, 60)
|
||||
screen.print("Up! ", 10, 60)
|
||||
})
|
||||
|
||||
|
||||
let num = 0
|
||||
|
||||
input.touchSensor.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText("Click! " + num, 10, 60)
|
||||
input.touchSensor1.onEvent(TouchSensorEvent.Bumped, () => {
|
||||
screen.print("Click! " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
input.remoteTopLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText("TOPLEFT " + num, 10, 60)
|
||||
input.remoteButtonTopLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.print("TOPLEFT " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
input.remoteTopRight.onEvent(ButtonEvent.Down, () => {
|
||||
screen.drawText("TOPRIGH " + num, 10, 60)
|
||||
input.remoteButtonTopRight.onEvent(ButtonEvent.Down, () => {
|
||||
screen.print("TOPRIGH " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
@ -54,7 +54,7 @@ loops.forever(() => {
|
||||
/*
|
||||
loops.forever(() => {
|
||||
let v = input.color.getColor()
|
||||
screen.drawText(10, 60, v + " ")
|
||||
screen.print(10, 60, v + " ")
|
||||
loops.pause(200)
|
||||
})
|
||||
*/
|
||||
*/
|
||||
|
@ -1,10 +1,26 @@
|
||||
namespace input {
|
||||
export class TouchSensor extends internal.AnalogSensor {
|
||||
button: Button;
|
||||
// keep TouchSensorEvent in sync with ButtonEvent
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.button = new Button()
|
||||
/**
|
||||
* Touch sensor interactions
|
||||
*/
|
||||
const enum TouchSensorEvent {
|
||||
//% block="pressed"
|
||||
Pressed = 4,
|
||||
//% block="bumped"
|
||||
Bumped = 1,
|
||||
//% block="released"
|
||||
Released = 3,
|
||||
}
|
||||
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class TouchSensor extends internal.AnalogSensor {
|
||||
private button: Button;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.button = new Button();
|
||||
}
|
||||
|
||||
_query() {
|
||||
@ -12,17 +28,51 @@ namespace input {
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
this.button.update(curr > 0)
|
||||
this.button._update(curr > 0)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
return DAL.DEVICE_TYPE_TOUCH
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if touch sensor is touched.
|
||||
* @param sensor the port to query the request
|
||||
*/
|
||||
//% help=input/touch/is-touched
|
||||
//% block="%sensor|is touched"
|
||||
//% blockId=touchIsTouched
|
||||
//% parts="touch"
|
||||
//% blockNamespace=input
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
isTouched() {
|
||||
return this.button.isPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a touch sensor is touched...
|
||||
* @param sensor the touch sensor that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
*/
|
||||
//% help=input/touch/on-event
|
||||
//% blockId=touchEvent block="on %sensor|%event"
|
||||
//% parts="touch"
|
||||
//% blockNamespace=input
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
onEvent(ev: TouchSensorEvent, body: () => void) {
|
||||
this.button.onEvent(<ButtonEvent><number>ev, body)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const touchSensorImpl: TouchSensor = new TouchSensor()
|
||||
|
||||
//% whenUsed
|
||||
export const touchSensor: Button = touchSensorImpl.button
|
||||
//% whenUsed block="touch sensor 1" weight=95 fixedInstance
|
||||
export const touchSensor1: TouchSensor = new TouchSensor(1)
|
||||
//% whenUsed block="touch sensor 2" weight=95 fixedInstance
|
||||
export const touchSensor2: TouchSensor = new TouchSensor(2)
|
||||
//% whenUsed block="touch sensor 3" weight=95 fixedInstance
|
||||
export const touchSensor3: TouchSensor = new TouchSensor(3)
|
||||
//% whenUsed block="touch sensor 4" weight=95 fixedInstance
|
||||
export const touchSensor4: TouchSensor = new TouchSensor(4)
|
||||
}
|
||||
|
@ -1,22 +1,85 @@
|
||||
const enum PromixityEvent {
|
||||
//% block="object near"
|
||||
ObjectNear = 1,
|
||||
//% block="object detected"
|
||||
ObjectDetected = 2
|
||||
}
|
||||
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class UltraSonicSensor extends internal.UartSensor {
|
||||
constructor() {
|
||||
super()
|
||||
private promixityThreshold: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.promixityThreshold = 10;
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
return DAL.DEVICE_TYPE_ULTRASONIC
|
||||
}
|
||||
|
||||
/** Get distance in mm */
|
||||
getDistance() {
|
||||
_query(): number {
|
||||
const d = this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
return d < this.promixityThreshold ? PromixityEvent.ObjectNear
|
||||
: d > this.promixityThreshold + 5 ? PromixityEvent.ObjectDetected
|
||||
: 0;
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
if (curr)
|
||||
control.raiseEvent(this._id, curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the given color is close
|
||||
* @param handler the code to run when detected
|
||||
*/
|
||||
//% help=input/ultrasonic/on-object-near
|
||||
//% block="on %sensor|object near"
|
||||
//% blockId=ultrasonicOnObjectClose
|
||||
//% parts="infraredsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Ultrasonic Sensor"
|
||||
onObjectNear(handler: () => void) {
|
||||
control.onEvent(this._id, PromixityEvent.ObjectNear, handler);
|
||||
if (this.distance() == PromixityEvent.ObjectNear)
|
||||
control.runInBackground(handler);
|
||||
}
|
||||
|
||||
setObjectNearThreshold(distance: number) {
|
||||
this.promixityThreshold = Math.max(1, Math.min(250, distance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance from the sonar in millimeters
|
||||
* @param sensor the ultrasonic sensor port
|
||||
*/
|
||||
//% help=input/ultrasonic/distance
|
||||
//% block="%sensor|distance"
|
||||
//% blockId=sonarGetDistance
|
||||
//% parts="ultrasonic"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Ultrasonic Sensor"
|
||||
distance() {
|
||||
// it supposedly also has an inch mode, but we stick to mm
|
||||
this._setMode(0)
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const ultrasonic: UltraSonicSensor = new UltraSonicSensor()
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 4"
|
||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 1"
|
||||
export const ultrasonic1: UltraSonicSensor = new UltraSonicSensor(1)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 2"
|
||||
export const ultrasonic2: UltraSonicSensor = new UltraSonicSensor(2)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 3"
|
||||
export const ultrasonic3: UltraSonicSensor = new UltraSonicSensor(3)
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
|
||||
//% color="#D42878"
|
||||
//% groups='["Brick buttons"]'
|
||||
namespace input {
|
||||
}
|
||||
|
||||
//% color="#8AC044" weight=90 icon="\uf185"
|
||||
//% groups='["Lights", "Screen", "Motors"]'
|
||||
//% groups='["Motors", "Brick"]'
|
||||
namespace output {
|
||||
}
|
||||
|
||||
|
@ -8,15 +8,15 @@
|
||||
"music.noteFrequency|param|name": "the note name, eg: Note.C",
|
||||
"music.playSound": "Start playing a sound and don't wait for it to finish.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
|
||||
"music.playSoundUntilDone": "Play a sound and wait until the sound is done.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
|
||||
"music.playSoundUntilDone|param|sound": "the melody to play, eg: 'g5:1'",
|
||||
"music.playSound|param|sound": "the melody to play, eg: 'g5:1'",
|
||||
"music.playSoundUntilDone|param|sound": "the melody to play, eg: music.sounds(Sounds.PowerUp)",
|
||||
"music.playSound|param|sound": "the melody to play, eg: music.sounds(Sounds.PowerUp)",
|
||||
"music.playTone": "Play a tone through the speaker for some amount of time.",
|
||||
"music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
|
||||
"music.playTone|param|ms": "tone duration in milliseconds (ms)",
|
||||
"music.rest": "Rest, or play silence, for some time (in milleseconds).",
|
||||
"music.rest|param|ms": "rest duration in milliseconds (ms)",
|
||||
"music.rest|param|ms": "rest duration in milliseconds (ms), eg: 100",
|
||||
"music.ringTone": "Play a tone.",
|
||||
"music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
|
||||
"music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz), eg: Note.C",
|
||||
"music.setTempo": "Set the tempo a number of beats per minute (bpm).",
|
||||
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
|
||||
"music.setVolume": "Set the output volume of the sound synthesizer.",
|
||||
|
@ -29,14 +29,14 @@
|
||||
"Sounds.Siren|block": "siren",
|
||||
"Sounds.Wawawawaa|block": "wawawawaa",
|
||||
"music.beat|block": "%fraction|beat",
|
||||
"music.changeTempoBy|block": "change tempo by (bpm)|%value",
|
||||
"music.changeTempoBy|block": "change tempo by %value|(bpm)",
|
||||
"music.noteFrequency|block": "%note",
|
||||
"music.playSoundUntilDone|block": "play sound %sound=music_sounds|until done",
|
||||
"music.playSound|block": "play sound %sound=music_sounds",
|
||||
"music.playTone|block": "play tone|at %note=device_note|for %duration=device_beat",
|
||||
"music.rest|block": "rest|for %duration=device_beat",
|
||||
"music.ringTone|block": "ring tone|at %note=device_note",
|
||||
"music.setTempo|block": "set tempo to (bpm)|%value",
|
||||
"music.setTempo|block": "set tempo to %value|(bpm)",
|
||||
"music.setVolume|block": "set volume %volume",
|
||||
"music.sounds|block": "%name",
|
||||
"music.stopAllSounds|block": "stop all sounds",
|
||||
|
@ -67,10 +67,11 @@ static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume)
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||
* @param ms tone duration in milliseconds (ms)
|
||||
*/
|
||||
//% help=music/play-tone weight=90
|
||||
//% help=music/play-tone
|
||||
//% blockId=music_play_note block="play tone|at %note=device_note|for %duration=device_beat"
|
||||
//% parts="headphone" async blockGap=8
|
||||
//% parts="headphone" async
|
||||
//% blockNamespace=music
|
||||
//% weight=76 blockGap=8
|
||||
void playTone(int frequency, int ms) {
|
||||
if (frequency <= 0) {
|
||||
_stopSound();
|
||||
|
7
libs/music/shims.d.ts
vendored
@ -18,10 +18,11 @@ declare namespace music {
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||
* @param ms tone duration in milliseconds (ms)
|
||||
*/
|
||||
//% help=music/play-tone weight=90
|
||||
//% help=music/play-tone
|
||||
//% blockId=music_play_note block="play tone|at %note=device_note|for %duration=device_beat"
|
||||
//% parts="headphone" async blockGap=8
|
||||
//% blockNamespace=music shim=music::playTone
|
||||
//% parts="headphone" async
|
||||
//% blockNamespace=music
|
||||
//% weight=76 blockGap=8 shim=music::playTone
|
||||
function playTone(frequency: int32, ms: int32): void;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.17",
|
||||
"version": "0.0.26",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@ -39,8 +39,8 @@
|
||||
"semantic-ui-less": "^2.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.9.2",
|
||||
"pxt-core": "2.0.29"
|
||||
"pxt-common-packages": "0.11.7",
|
||||
"pxt-core": "2.3.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
@ -68,10 +68,10 @@
|
||||
"appTheme": {
|
||||
"accentColor": "#0089BF",
|
||||
"logoUrl": "https://lego.makecode.com",
|
||||
"logo": "./static/logo.svg",
|
||||
"docsLogo": "./static/logo.square.svg",
|
||||
"portraitLogo": "./static/logo.square.svg",
|
||||
"footerLogo": "./static/logo.square.svg",
|
||||
"logo": "./static/lego_education_logo.png",
|
||||
"docsLogo": "./static/lego-logo.svg",
|
||||
"portraitLogo": "./static/lego-logo.svg",
|
||||
"footerLogo": "./static/lego-logo.svg",
|
||||
"cardLogo": "./static/icons/android-chrome-192x192.png",
|
||||
"appLogo": "./static/icons/android-chrome-192x192.png",
|
||||
"organization": "Microsoft MakeCode",
|
||||
@ -89,10 +89,6 @@
|
||||
"name": "About",
|
||||
"path": "/about"
|
||||
},
|
||||
{
|
||||
"name": "Examples",
|
||||
"path": "#projects:Examples"
|
||||
},
|
||||
{
|
||||
"name": "Blocks",
|
||||
"path": "/blocks"
|
||||
@ -104,22 +100,14 @@
|
||||
{
|
||||
"name": "Reference",
|
||||
"path": "/reference"
|
||||
},
|
||||
{
|
||||
"name": "Buy",
|
||||
"path": "https://www.lego.com/en-us/mindstorms/products/mindstorms-ev3-31313"
|
||||
}
|
||||
],
|
||||
"galleries": {
|
||||
"Make": "projects",
|
||||
"Examples": "examples"
|
||||
},
|
||||
"sideDoc": "tutorials/getting-started",
|
||||
"showHomeScreen": true,
|
||||
"homeScreenHero": "./static/hero.png",
|
||||
"invertedMenu": false,
|
||||
"invertedMonaco": false,
|
||||
"monacoToolbox": true,
|
||||
"invertedToolbox": true,
|
||||
"exampleGallery": "examples",
|
||||
"hasAudio": true,
|
||||
"usbHelp": [],
|
||||
"extendEditor": true,
|
||||
|
157
scripts/rgf2png.js
Executable file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs")
|
||||
const zlib = require("zlib")
|
||||
|
||||
function compressImg(fn) {
|
||||
const rgf = fs.readFileSync(fn)
|
||||
|
||||
const width = rgf[0]
|
||||
const height = rgf[1]
|
||||
|
||||
const expSz = ((width + 7) >> 3) * height + 2
|
||||
|
||||
console.log(`w=${width} h=${height} sz=${rgf.length} exp=${expSz}`)
|
||||
|
||||
let crcTable
|
||||
|
||||
function crc32(buf) {
|
||||
if (!crcTable) {
|
||||
crcTable = []
|
||||
for (let i = 0; i < 256; i++) {
|
||||
let curr = i;
|
||||
for (let j = 0; j < 8; j++) {
|
||||
if (curr & 1) {
|
||||
curr = 0xedb88320 ^ (curr >>> 1);
|
||||
} else {
|
||||
curr = curr >>> 1;
|
||||
}
|
||||
}
|
||||
crcTable[i] = curr
|
||||
}
|
||||
}
|
||||
|
||||
let crc = -1;
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
||||
}
|
||||
return (crc ^ -1) >>> 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Width 4 bytes
|
||||
Height 4 bytes
|
||||
Bit depth 1 byte
|
||||
Colour type 1 byte
|
||||
Compression method 1 byte
|
||||
Filter method 1 byte
|
||||
Interlace method 1 byte
|
||||
*/
|
||||
|
||||
const chunks = []
|
||||
|
||||
function addChunk(mark, addsize) {
|
||||
const buf = Buffer.alloc(mark.length + addsize)
|
||||
for (let i = 0; i < mark.length; ++i) {
|
||||
buf[i] = mark.charCodeAt(i)
|
||||
}
|
||||
chunks.push(buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
const hd = addChunk("IHDR", 4 + 4 + 5)
|
||||
hd.writeInt32BE(width, 4)
|
||||
hd.writeInt32BE(height, 8)
|
||||
hd[12] = 1 // bit depth
|
||||
hd[13] = 0 // color type - grayscale
|
||||
hd[14] = 0 // compression - deflate
|
||||
hd[15] = 0 // filter method
|
||||
hd[16] = 0 // interlace method - no interlace
|
||||
|
||||
const scanlines = []
|
||||
const scanlen = (width + 7) >> 3
|
||||
|
||||
let srcptr = 2
|
||||
let srcmask = 0x01
|
||||
for (let y = 0; y < height; ++y) {
|
||||
const scan = Buffer.alloc(1 + scanlen)
|
||||
scanlines.push(scan)
|
||||
let dstptr = 1
|
||||
let dstmask = 0x80
|
||||
for (let x = 0; x < width; ++x) {
|
||||
if (!(rgf[srcptr] & srcmask)) {
|
||||
scan[dstptr] |= dstmask
|
||||
}
|
||||
dstmask >>= 1;
|
||||
if (dstmask == 0) {
|
||||
dstmask = 0x80
|
||||
dstptr++
|
||||
}
|
||||
srcmask <<= 1;
|
||||
if (srcmask > 0x80) {
|
||||
srcmask = 0x01
|
||||
srcptr++
|
||||
}
|
||||
}
|
||||
if (srcmask != 0x01) {
|
||||
srcmask = 0x01
|
||||
srcptr++
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// seems to increase file size
|
||||
scan[0] = 1 // sub
|
||||
let prev = 0
|
||||
for (let i = 1; i < scan.length; ++i) {
|
||||
let p = scan[i]
|
||||
scan[i] = (p - prev) & 0xff
|
||||
prev = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dat = zlib.deflateSync(Buffer.concat(scanlines), {
|
||||
level: 9
|
||||
})
|
||||
const idat = addChunk("IDAT", dat.length)
|
||||
dat.copy(idat, 4)
|
||||
addChunk("IEND", 0)
|
||||
|
||||
const output = [new Buffer([137, 80, 78, 71, 13, 10, 26, 10])]
|
||||
|
||||
function intBuf(v) {
|
||||
let b = new Buffer(4)
|
||||
b.writeUInt32BE(v, 0)
|
||||
return b
|
||||
}
|
||||
for (let ch of chunks) {
|
||||
output.push(intBuf(ch.length - 4))
|
||||
output.push(ch)
|
||||
output.push(intBuf(crc32(ch)))
|
||||
}
|
||||
|
||||
let outp = Buffer.concat(output)
|
||||
return outp
|
||||
}
|
||||
|
||||
let sz = 0
|
||||
let bf
|
||||
let out = {}
|
||||
for (let i = 2; i < process.argv.length; ++i) {
|
||||
let fn = process.argv[i]
|
||||
let m = /([^\/]+\/[^/]+)\.rgf$/.exec(fn)
|
||||
let bn = m[1]
|
||||
bf = compressImg(fn)
|
||||
out[bn] = "data:image/png;base64," + bf.toString("base64")
|
||||
sz += bf.length
|
||||
}
|
||||
|
||||
console.log("total " + sz)
|
||||
fs.writeFileSync("out.json", JSON.stringify(out, null, 4))
|
||||
fs.writeFileSync("out.png", bf)
|
||||
|
||||
//if (require("os").platform() == "darwin")
|
||||
// require('child_process').execSync("afplay out.wav")
|
||||
|
||||
// TODO also play on Windows
|
46
scripts/rsf2wav.js
Executable file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs")
|
||||
const rsf = fs.readFileSync(process.argv[2])
|
||||
|
||||
const fmt = rsf.readInt16BE(0) // 0x0100
|
||||
if (fmt != 0x0100) {
|
||||
throw new Error("Invalid input format: " + fmt)
|
||||
}
|
||||
const size = rsf.readInt16BE(2)
|
||||
const samplerate = rsf.readInt16BE(4)
|
||||
const repeat = rsf.readInt16BE(6)
|
||||
|
||||
const datasize = rsf.length - 8
|
||||
|
||||
const wavHd = new Buffer(44)
|
||||
|
||||
function writeMark(off, mark) {
|
||||
for (let i = 0; i < mark.length; ++i) {
|
||||
wavHd[off + i] = mark.charCodeAt(i)
|
||||
}
|
||||
}
|
||||
|
||||
writeMark(0, 'RIFF')
|
||||
wavHd.writeInt32LE(datasize + 36, 4)
|
||||
writeMark(8, 'WAVE')
|
||||
writeMark(12, 'fmt ')
|
||||
wavHd.writeInt32LE(16, 16) // fmt size
|
||||
wavHd.writeInt16LE(1, 20) // PCM
|
||||
wavHd.writeInt16LE(1, 22) // mono, 1ch
|
||||
wavHd.writeInt32LE(samplerate, 24)
|
||||
wavHd.writeInt32LE(samplerate, 28) // byterate
|
||||
wavHd.writeInt16LE(1, 32) // block align
|
||||
wavHd.writeInt16LE(8, 34) // bits per sample
|
||||
writeMark(36, 'data')
|
||||
wavHd.writeInt32LE(datasize, 40)
|
||||
|
||||
const wav = Buffer.concat([wavHd, rsf.slice(8)])
|
||||
|
||||
console.log("writing out.wav; " + samplerate + "Hz")
|
||||
fs.writeFileSync("out.wav", wav)
|
||||
|
||||
if (require("os").platform() == "darwin")
|
||||
require('child_process').execSync("afplay out.wav")
|
||||
|
||||
// TODO also play on Windows
|
@ -25,7 +25,7 @@ namespace pxsim {
|
||||
export class DalBoard extends CoreBoard implements
|
||||
AccelerometerBoard,
|
||||
CommonBoard,
|
||||
LightBoard,
|
||||
// LightBoard,
|
||||
LightSensorBoard,
|
||||
MicrophoneBoard,
|
||||
MusicBoard,
|
||||
@ -34,7 +34,7 @@ namespace pxsim {
|
||||
InfraredBoard,
|
||||
CapTouchBoard {
|
||||
// state & update logic for component services
|
||||
neopixelState: CommonNeoPixelState;
|
||||
// neopixelState: CommonNeoPixelState;
|
||||
buttonState: EV3ButtonState;
|
||||
slideSwitchState: SlideSwitchState;
|
||||
lightSensorState: AnalogSensorState;
|
||||
@ -62,11 +62,12 @@ namespace pxsim {
|
||||
this.builtinParts["buttons"] = this.buttonState = new EV3ButtonState();
|
||||
this.builtinParts["light"] = this.lightState = new EV3LightState();
|
||||
this.builtinParts["screen"] = this.screenState = new EV3ScreenState();
|
||||
this.builtinParts["audio"] = this.audioState = new AudioState();
|
||||
|
||||
/*this.builtinParts["neopixel"] = this.neopixelState = new CommonNeoPixelState();
|
||||
this.builtinParts["buttonpair"] = this.buttonState = new CommonButtonState();
|
||||
|
||||
this.builtinParts["switch"] = this.slideSwitchState = new SlideSwitchState();
|
||||
this.builtinParts["audio"] = this.audioState = new AudioState();
|
||||
this.builtinParts["lightsensor"] = this.lightSensorState = new AnalogSensorState(DAL.DEVICE_ID_LIGHT_SENSOR, 0, 255);
|
||||
this.builtinParts["thermometer"] = this.thermometerState = new AnalogSensorState(DAL.DEVICE_ID_THERMOMETER, -5, 50);
|
||||
this.builtinParts["soundsensor"] = this.microphoneState = new AnalogSensorState(DAL.DEVICE_ID_TOUCH_SENSOR + 1, 0, 255);
|
||||
@ -174,9 +175,9 @@ namespace pxsim {
|
||||
return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
|
||||
}
|
||||
|
||||
defaultNeopixelPin() {
|
||||
return this.edgeConnectorState.getPin(CPlayPinName.D8);
|
||||
}
|
||||
//defaultNeopixelPin() {
|
||||
// return this.edgeConnectorState.getPin(CPlayPinName.D8);
|
||||
//}
|
||||
|
||||
getDefaultPitchPin() {
|
||||
return this.edgeConnectorState.getPin(CPlayPinName.D6);
|
||||
|
@ -480,6 +480,7 @@ namespace pxsim.visuals {
|
||||
this.screenCanvasCtx.putImageData(this.screenCanvasData, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
private updateNeoPixels() {
|
||||
let state = this.board;
|
||||
if (!state || !state.neopixelState) return;
|
||||
@ -509,6 +510,7 @@ namespace pxsim.visuals {
|
||||
if (p_inner) svg.filter(p_inner, `url(#neopixelglow)`);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private updateSound() {
|
||||
let state = this.board;
|
||||
|
@ -6,5 +6,8 @@
|
||||
],
|
||||
"approvedRepos": [
|
||||
]
|
||||
},
|
||||
"galleries": {
|
||||
"Maker Activities": "maker"
|
||||
}
|
||||
}
|
@ -34,13 +34,6 @@ span.blocklyTreeLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.blocklyFlyoutBackground {
|
||||
fill: #282828 !important;
|
||||
}
|
||||
.monacoFlyout {
|
||||
background: rgba(40, 40, 40, 0.9);
|
||||
}
|
||||
|
||||
/* Search box */
|
||||
#blocklySearchArea {
|
||||
margin: 0.5rem;
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
/* Lego colors */
|
||||
@red: @brightRed;
|
||||
@blue: #008ad2;
|
||||
@blue: #00a5c8; /*#008ad2;*/
|
||||
@yellow: #fccd00;
|
||||
@orange: #fa7f2a;
|
||||
@green: @brightYellowishGreen;
|
||||
@ -96,9 +96,11 @@
|
||||
Menu
|
||||
--------------------*/
|
||||
|
||||
@mainMenuBackground: #f4f7f9;
|
||||
@mainMenuInvertedBackground: @yellow;
|
||||
@mainMenuTutorialBackground: @orange;
|
||||
|
||||
|
||||
@tutorialSelectedMenuColor: @blue;
|
||||
|
||||
/*-------------------
|
||||
@ -117,6 +119,8 @@
|
||||
@editorToolsBackground: #fcfbfa;
|
||||
@blocklySvgColor: #ecf6ff;
|
||||
|
||||
@homeScreenBackground: #EAEEEF;
|
||||
|
||||
/*-------------------
|
||||
Full screen
|
||||
--------------------*/
|
||||
@ -152,3 +156,13 @@
|
||||
@blocklyRowHeightComputer: 50px;
|
||||
@blocklyRowHeightTablet: 50px;
|
||||
@blocklyRowHeightMobile: 50px;
|
||||
|
||||
|
||||
/*-------------------
|
||||
Flyout
|
||||
--------------------*/
|
||||
|
||||
@flyoutLabelColor: white;
|
||||
@blocklyFlyoutColor: #282828;
|
||||
@blocklyFlyoutColorOpacity: 0.9;
|
||||
@monacoFlyoutColor: rgba(40, 40, 40,0.9);
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
/* Menu bar colors */
|
||||
#menubar .ui.item {
|
||||
color: @red;
|
||||
color: #373737;
|
||||
}
|
||||
.fullscreensim #menubar .ui.menu {
|
||||
box-shadow: none !important;
|
||||
@ -59,11 +59,17 @@
|
||||
/* Editor menu toggle */
|
||||
#menubar .ui.menu.fixed .item.editor-menuitem .ui.grid {
|
||||
background: @blue !important;
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
|
||||
#menubar .ui.menu.fixed .ui.item.editor-menuitem .item:not(.active) {
|
||||
color: white;
|
||||
}
|
||||
#menubar .ui.menu.fixed .ui.item.editor-menuitem .item {
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
#menubar .ui.menu.fixed .ui.item.editor-menuitem .item.active {
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
.sandboxfooter a:not(.thin) {
|
||||
color:white !important;
|
||||
|
@ -49,10 +49,10 @@
|
||||
/* Modules */
|
||||
@accordion : 'default';
|
||||
@checkbox : 'default';
|
||||
@dimmer : 'default';
|
||||
@dimmer : 'pxt';
|
||||
@dropdown : 'default';
|
||||
@embed : 'default';
|
||||
@modal : 'default';
|
||||
@modal : 'pxt';
|
||||
@nag : 'default';
|
||||
@popup : 'default';
|
||||
@progress : 'default';
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
/* Views */
|
||||
@ad : 'default';
|
||||
@card : 'default';
|
||||
@card : 'pxt';
|
||||
@comment : 'default';
|
||||
@feed : 'default';
|
||||
@item : 'default';
|
||||
|