Compare commits

..

53 Commits

Author SHA1 Message Date
4e99cd3ef1 0.0.26 2017-10-27 19:23:01 +01:00
57647318c4 Sensor fixes 2017-10-27 19:18:56 +01:00
2720698864 Fix infinite loop 2017-10-27 19:18:47 +01:00
c0bab4877a Merge branch 'master' of github.com:Microsoft/pxt-ev3 2017-10-27 15:17:24 +01:00
d2a1d10ada Add converter from RGF to PNG 2017-10-27 15:17:21 +01:00
bcb68d937d Merge branch 'master' of https://github.com/microsoft/pxt-ev3 2017-10-27 02:52:47 -07:00
05a8395028 stop all motors 2017-10-27 02:52:42 -07:00
3a1601a419 Add rsf2wav.js 2017-10-27 10:42:33 +01:00
712c2178d2 simplify motor API 2017-10-27 01:47:25 -07:00
12cdad72c8 added puppet 2017-10-27 00:13:51 -07:00
95076f8f24 differentiate large/medium motors 2017-10-27 00:09:00 -07:00
6391620373 added 2 more activities 2017-10-26 23:58:34 -07:00
86212e2153 added sound of color 2017-10-26 23:46:55 -07:00
98e430f3c1 added example of converted lesson 2017-10-26 22:19:16 -07:00
5c7e856e7b removed incorrect buy link 2017-10-26 21:57:48 -07:00
a47988913e 0.0.25 2017-10-26 21:27:51 -07:00
ea72dba6c7 Merge pull request #17 from Microsoft/irevents
Ultrasonic + IR events + Remote events
2017-10-27 06:25:02 +02:00
215e846a54 refactored remote button 2017-10-26 21:10:37 -07:00
21b34cb459 simplified events 2017-10-26 20:57:18 -07:00
282134f5dc refactoring IR 2017-10-26 20:51:13 -07:00
6b44352839 event for ultrasonic module 2017-10-26 20:38:17 -07:00
9a883d5672 Merge branch 'master' into irevents 2017-10-26 20:21:06 -07:00
59ce4338d3 renaming IR events 2017-10-26 20:20:24 -07:00
90560050b8 Merge pull request #16 from Microsoft/fonts
Mounting events on various sensors
2017-10-27 05:19:36 +02:00
2c72173bfe Use the _query() infrastructure for polling 2017-10-25 13:34:05 +02:00
1a5992408b added event for color changes 2017-10-24 23:10:27 -07:00
0e1a3b7e6b adding setpixel 2017-10-24 22:05:24 -07:00
ea6bfa03bd touched -> pressed 2017-10-24 21:55:37 -07:00
20d584db2b 0.0.24 2017-10-24 21:18:16 -07:00
0e4e0d8899 0.0.23 2017-10-24 21:09:56 -07:00
a18a690417 Merge pull request #12 from Microsoft/motors
Converting motors to fixed instances
2017-10-25 06:09:27 +02:00
c9d57c5e8d enabling banner 2017-10-24 21:08:02 -07:00
7e9d42a571 reset motors on start 2017-10-24 20:28:31 -07:00
1b51320edb pausing while running motor 2017-10-24 20:20:07 -07:00
4f44238237 use fixed instances for motors 2017-10-24 20:16:33 -07:00
c8ffa0ded7 fixed test 2017-10-24 18:49:15 -07:00
6b07d5f716 0.0.22 2017-10-24 18:48:30 -07:00
8784e23b60 fixed build link 2017-10-24 17:01:36 -07:00
4b8409fbc0 0.0.21 2017-10-24 16:56:52 -07:00
3237978cba Merge pull request #4 from Microsoft/blockupdate
Blocks update
2017-10-24 16:56:32 -07:00
33c8902050 aligning groups with hardware name components 2017-10-24 16:52:13 -07:00
fa6c81cf80 buttons -> brick buttons 2017-10-24 16:25:03 -07:00
46175fc7db separating touch sensor stuff 2017-10-24 15:58:47 -07:00
e6ef86101f more renaming 2017-10-24 15:37:48 -07:00
c4d3d7634e fixed naming of sonar 2017-10-24 15:35:42 -07:00
b0380fbef8 more annotations 2017-10-24 15:33:28 -07:00
c85c68ab68 fixing color / gyro 2017-10-24 15:22:07 -07:00
334d5aca9a on/off field editors on motors 2017-10-24 15:03:21 -07:00
1330a0fb82 fixed gyro def 2017-10-24 14:54:36 -07:00
005447ce44 4 times more sensors\! 2017-10-24 19:58:52 +01:00
60d5271de2 Merge branch 'master' into blockupdate 2017-10-24 10:02:27 -07:00
5d5d78ced0 compiled strings 2017-10-24 09:47:30 -07:00
fe46461c4c adding a few more blocks 2017-10-24 05:30:05 -07:00
33 changed files with 1167 additions and 436 deletions

1
.gitignore vendored
View File

@ -31,3 +31,4 @@ videos/**
lib/
.vscode/
bin
scripts/out.*

View File

@ -1,6 +1,6 @@
# LEGO Mindstorms EV3 target for PXT
[![Build Status](https://ci2.dot.net/buildStatus/icon?job=Private/pxt_project_pink/master/pxt-ev3_Push)](https://ci2.dot.net/job/Private/job/pxt_project_pink/job/master/job/pxt-ev3_Push/)
[![Build Status](https://ci2.dot.net/buildStatus/icon?job=Private/pxt_project_rainbow/master/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/

47
docs/maker.md Normal file
View 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"
}
]
```

View 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
View 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)
})
```

View 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))
})
```

View 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)
})
```

View 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))
})
```

BIN
docs/static/hero.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/static/maker/intruder-detector.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
docs/static/maker/puppet.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

BIN
docs/static/maker/security-gadget.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/static/maker/sound-machine.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
docs/static/maker/sound-of-color.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

View File

@ -9,6 +9,7 @@
"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.",
@ -20,51 +21,70 @@
"input": "Respond to and read data from buttons and sensors.",
"input.Button": "Generic button class, for device buttons and sensors.",
"input.Button.isPressed": "Check if button is currently pressed or not.",
"input.Button.onEvent": "Do something when a button or sensor is clicked, double clicked, etc...",
"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.getAmbientLight": "Get current ambient light value from the color sensor.",
"input.ColorSensor.getColor": "Get the current color from the color sensor.",
"input.ColorSensor.getReflectedLight": "Get current reflected light value from the color sensor.",
"input.UltraSonicSensor.getDistance": "Get distance in mm",
"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.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.switchMotor": "Switch the motor on or off.",
"output.switchMotor|param|on": "1 to turn the motor on, 0 to turn it off",
"output.switchMotor|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."
}

View File

@ -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,36 +20,89 @@
"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.Button.isPressed|block": "%button|is pressed",
"input.Button.onEvent|block": "on %button|%event",
"input.Button.wasPressed|block": "%button|was pressed",
"input.ColorSensor.getAmbientLight|block": "%color| ambient light",
"input.ColorSensor.getColor|block": "%color| color",
"input.ColorSensor.getReflectedLight|block": "%color| reflected light",
"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.color|block": "color sensor",
"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.touchSensor|block": "touch sensor",
"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.switchMotor|block": "turn motor %out|%on",
"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",
@ -51,7 +111,12 @@
"{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"
}

View File

@ -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)
}
}
@ -87,12 +86,10 @@ namespace input {
//% help=input/button/is-pressed
//% block="%button|is pressed"
//% blockId=buttonIsPressed
//% parts="buttonpair"
//% parts="brick"
//% blockNamespace=input
//% button.fieldEditor="gridpicker"
//% button.fieldOptions.width=220
//% button.fieldOptions.columns=3
//% weight=81 blockGap=8
//% group="Brick"
isPressed() {
return this._isPressed
}
@ -104,12 +101,10 @@ namespace input {
//% help=input/button/was-pressed
//% block="%button|was pressed"
//% blockId=buttonWasPressed
//% parts="buttonpair"
//% parts="brick"
//% blockNamespace=input
//% button.fieldEditor="gridpicker"
//% button.fieldOptions.width=220
//% button.fieldOptions.columns=3
//% weight=80 blockGap=8
//% group="Brick"
wasPressed() {
const r = this._wasPressed
this._wasPressed = false
@ -117,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
//% blockId=buttonEvent block="on %button|%event"
//% parts="buttonpair"
//% parts="brick"
//% blockNamespace=input
//% button.fieldEditor="gridpicker"
//% button.fieldOptions.width=220
//% button.fieldOptions.columns=3
//% weight=99
//% weight=99 blockGap=8
//% group="Brick"
onEvent(ev: ButtonEvent, body: () => void) {
control.onEvent(this._id, ev, body)
}
@ -166,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())
}
@ -183,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)
}
@ -240,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
@ -258,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;
}
}

View File

@ -9,13 +9,21 @@ 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,
}
@ -23,8 +31,8 @@ namespace input {
//% fixedInstances
export class ColorSensor extends internal.UartSensor {
constructor() {
super()
constructor(port: number) {
super(port)
}
_deviceType() {
@ -35,6 +43,35 @@ namespace input {
this._setMode(m)
}
_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
@ -45,7 +82,8 @@ namespace input {
//% parts="colorsensor"
//% blockNamespace=input
//% weight=65 blockGap=8
getAmbientLight() {
//% group="Color Sensor"
ambientLight() {
this.setMode(ColorSensorMode.Ambient)
return this.getNumber(NumberFormat.UInt8LE, 0)
}
@ -60,7 +98,8 @@ namespace input {
//% parts="colorsensor"
//% blockNamespace=input
//% weight=64 blockGap=8
getReflectedLight(): number {
//% group="Color Sensor"
reflectedLight(): number {
this.setMode(ColorSensorMode.Reflect)
return this.getNumber(NumberFormat.UInt8LE, 0)
}
@ -75,12 +114,22 @@ namespace input {
//% parts="colorsensor"
//% blockNamespace=input
//% weight=66 blockGap=8
getColor(): ColorSensorColor {
//% group="Color Sensor"
color(): ColorSensorColor {
this.setMode(ColorSensorMode.Color)
return this.getNumber(NumberFormat.UInt8LE, 0)
}
}
//% whenUsed block="color sensor" weight=95 fixedInstance
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)
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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 {
}

View File

@ -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,88 +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)
}
/**
* Switch the motor on or off.
* @param out the output connection that the motor is connected to
* @param on 1 to turn the motor on, 0 to turn it off
* Stops all motors
*/
//% blockId=output_switch block="turn motor %out|%on"
//% weight=90 group="Motors"
//% on.fieldEditor="toggle"
export function switchMotor(out: Output, on: number, useBrake = false) {
if (on == 0) {
output.stop(out, useBrake);
} else {
output.start(out);
//% 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)
}
//% fixedInstances
export class Motor extends control.Component {
private port: Output;
private large: boolean;
private brake: boolean;
constructor(port: Output, large: boolean) {
super();
this.port = port;
this.large = large;
this.brake = false;
}
}
/**
* Turn motor off.
* @param out the output connection that the motor is connected to
*/
//% blockId=output_stop block="turn motor %out|off"
//% weight=90 group="Motors"
//% deprecated=1
export function stop(out: Output, useBrake = false) {
let b = mkCmd(out, DAL.opOutputStop, 1)
b.setNumber(NumberFormat.UInt8LE, 2, useBrake ? 1 : 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"
//% deprecated=1
export function start(out: Output) {
if (currentSpeed[out] == -1) setSpeed(out, 50)
let b = mkCmd(out, DAL.opOutputStart, 0)
writePWM(b)
}
export function reset(out: Output) {
let b = mkCmd(out, DAL.opOutputReset, 0)
writePWM(b)
}
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) {
@ -147,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),
@ -163,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;
@ -218,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) {

View File

@ -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()

View File

@ -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)
})
*/
*/

View File

@ -1,12 +1,26 @@
// keep TouchSensorEvent in sync with ButtonEvent
/**
* 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 {
button: Button;
private button: Button;
constructor() {
super()
this.button = new Button()
constructor(port: number) {
super(port)
this.button = new Button();
}
_query() {
@ -14,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 block="touch sensor" weight=95 fixedInstance
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)
}

View File

@ -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)
}

View File

@ -4,7 +4,7 @@ namespace input {
}
//% color="#8AC044" weight=90 icon="\uf185"
//% groups='["Lights", "Screen", "Motors"]'
//% groups='["Motors", "Brick"]'
namespace output {
}

View File

@ -1,6 +1,6 @@
{
"name": "pxt-ev3",
"version": "0.0.20",
"version": "0.0.26",
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
"private": true,
"keywords": [

View File

@ -89,10 +89,6 @@
"name": "About",
"path": "/about"
},
{
"name": "Examples",
"path": "#projects:Examples"
},
{
"name": "Blocks",
"path": "/blocks"
@ -104,18 +100,14 @@
{
"name": "Reference",
"path": "/reference"
},
{
"name": "Buy",
"path": "https://www.lego.com/en-us/mindstorms/products/mindstorms-ev3-31313"
}
],
"useStartPage": true,
"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
View 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
View 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

View File

@ -6,5 +6,8 @@
],
"approvedRepos": [
]
},
"galleries": {
"Maker Activities": "maker"
}
}