Compare commits
117 Commits
Author | SHA1 | Date | |
---|---|---|---|
51a14596cd | |||
8518c446cd | |||
2f69df0d9d | |||
1789d0ce21 | |||
d0809510c4 | |||
6b9c0eaf65 | |||
52bdf94233 | |||
fd50ed8f7c | |||
ba0eb93b0f | |||
9a4ed45797 | |||
820fdf3a3c | |||
348d5ffc26 | |||
95e47a0b25 | |||
c3312ed5d1 | |||
b7cdc7d0fe | |||
dde5a35cd9 | |||
be398d84ee | |||
4445acce7a | |||
d6d8b0655b | |||
216aa1ddaf | |||
783a561941 | |||
c916664ae7 | |||
4b836ede1b | |||
52fdaeec99 | |||
2aaa45e10d | |||
7993363e89 | |||
4d671f6cb0 | |||
cc020d5a81 | |||
5c39862a44 | |||
e0e5c95989 | |||
800b4ad224 | |||
40c3b4b0cf | |||
64bdc35e6f | |||
2b5f702bb6 | |||
1c81ecd23f | |||
4d223374b5 | |||
dd9cf9014f | |||
eb11d7926c | |||
609740dc48 | |||
955a2c9757 | |||
02838e6c30 | |||
b0c54e84e6 | |||
b6644b7a23 | |||
3c4c38eb59 | |||
29aba7b10b | |||
7427142243 | |||
436500babb | |||
82be4e344b | |||
81bfca4ed6 | |||
c35dbdd38f | |||
1bc93013e6 | |||
58148eb1c3 | |||
a7c62b45b2 | |||
bd765d49ee | |||
383ca5467d | |||
e240e3b394 | |||
7affbf8cb6 | |||
4dff282633 | |||
5d470fdcef | |||
f30eac41e9 | |||
d7f46c0fb5 | |||
58384017f2 | |||
01f7fe633c | |||
a9a9a89811 | |||
7e2251d8ac | |||
1903a6e347 | |||
2fb75a2d83 | |||
0da175a8cd | |||
f01370e4fd | |||
751df2fe8c | |||
8be4bb11d8 | |||
342e714ae2 | |||
fb31b81f7e | |||
8204995749 | |||
85c14bb05a | |||
c398a5a133 | |||
a1b059171b | |||
afaedaa0b2 | |||
0aa41e9a64 | |||
88df2e14cb | |||
180f32f25c | |||
995527675a | |||
84eb849bc7 | |||
5e0e35b4bd | |||
300a2c1476 | |||
703bd01931 | |||
75a65eeab2 | |||
38a9f153f7 | |||
3c5dae8c7b | |||
85345969d3 | |||
ac1e5d2846 | |||
11b4bbc07e | |||
7f5b8aed99 | |||
c989e2fdab | |||
d3dcb5de85 | |||
9cca35d49f | |||
7123bfecd3 | |||
c8ac770983 | |||
aa031036ee | |||
a7d002d949 | |||
93fd8c8c78 | |||
1765ca2d35 | |||
1ab7ae6cfa | |||
3acf4e9ac5 | |||
ef5fa9ae82 | |||
e1f7a5b8cf | |||
2c73bfc813 | |||
d78d9c8686 | |||
2157af3e63 | |||
eac3e183c3 | |||
785ddff706 | |||
e07d6e3a31 | |||
763ad3f763 | |||
919a03951c | |||
9e427898ae | |||
60bf3a17d3 | |||
0529759a80 |
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
require("./editor")
|
require("./editor/deploy")
|
||||||
|
|
||||||
declare namespace pxt.editor {
|
declare namespace pxt.editor {
|
||||||
function deployCoreAsync(resp: pxtc.CompileResult, disconnect?: boolean): Promise<void>;
|
function deployCoreAsync(resp: pxtc.CompileResult, disconnect?: boolean): Promise<void>;
|
||||||
|
66
docs/static/fonts/icons/iconfont.css
vendored
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont";
|
font-family: "iconfont";
|
||||||
src: url("iconfont.eot?e05611aaee246c1da118a83eaf515de9?#iefix") format("embedded-opentype"),
|
src: url("iconfont.eot?73552ec404b3a3d3769a3f04fa58c2c4?#iefix") format("embedded-opentype"),
|
||||||
url("iconfont.woff2?e05611aaee246c1da118a83eaf515de9") format("woff2"),
|
url("iconfont.woff2?73552ec404b3a3d3769a3f04fa58c2c4") format("woff2"),
|
||||||
url("iconfont.woff?e05611aaee246c1da118a83eaf515de9") format("woff");
|
url("iconfont.woff?73552ec404b3a3d3769a3f04fa58c2c4") format("woff");
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
@ -28,3 +28,63 @@ url("iconfont.woff?e05611aaee246c1da118a83eaf515de9") format("woff");
|
|||||||
.icon-gyro:before {
|
.icon-gyro:before {
|
||||||
content: "\f104";
|
content: "\f104";
|
||||||
}
|
}
|
||||||
|
.icon-addpackage:before {
|
||||||
|
content: "\f105";
|
||||||
|
}
|
||||||
|
.icon-brick:before {
|
||||||
|
content: "\f106";
|
||||||
|
}
|
||||||
|
.icon-controls:before {
|
||||||
|
content: "\f107";
|
||||||
|
}
|
||||||
|
.icon-functions:before {
|
||||||
|
content: "\f108";
|
||||||
|
}
|
||||||
|
.icon-list:before {
|
||||||
|
content: "\f109";
|
||||||
|
}
|
||||||
|
.icon-logic:before {
|
||||||
|
content: "\f10a";
|
||||||
|
}
|
||||||
|
.icon-loops:before {
|
||||||
|
content: "\f10b";
|
||||||
|
}
|
||||||
|
.icon-math:before {
|
||||||
|
content: "\f10c";
|
||||||
|
}
|
||||||
|
.icon-motors:before {
|
||||||
|
content: "\f10d";
|
||||||
|
}
|
||||||
|
.icon-music:before {
|
||||||
|
content: "\f10e";
|
||||||
|
}
|
||||||
|
.icon-sensors:before {
|
||||||
|
content: "\f10f";
|
||||||
|
}
|
||||||
|
.icon-text:before {
|
||||||
|
content: "\f110";
|
||||||
|
}
|
||||||
|
.icon-variables:before {
|
||||||
|
content: "\f111";
|
||||||
|
}
|
||||||
|
.icon-advancedcollapsed:before {
|
||||||
|
content: "\f112";
|
||||||
|
}
|
||||||
|
.icon-advancedexpanded:before {
|
||||||
|
content: "\f113";
|
||||||
|
}
|
||||||
|
.icon-cancel:before {
|
||||||
|
content: "\f114";
|
||||||
|
}
|
||||||
|
.icon-check:before {
|
||||||
|
content: "\f115";
|
||||||
|
}
|
||||||
|
.icon-download:before {
|
||||||
|
content: "\f116";
|
||||||
|
}
|
||||||
|
.icon-save:before {
|
||||||
|
content: "\f117";
|
||||||
|
}
|
||||||
|
.icon-blocks:before {
|
||||||
|
content: "\f118";
|
||||||
|
}
|
||||||
|
BIN
docs/static/fonts/icons/iconfont.eot
vendored
60
docs/static/fonts/icons/iconfont.svg
vendored
@ -19,6 +19,66 @@
|
|||||||
<glyph glyph-name="gyro"
|
<glyph glyph-name="gyro"
|
||||||
unicode=""
|
unicode=""
|
||||||
horiz-adv-x="23.578015492438215" d=" M17 0H6.4A5.901881224640355 5.901881224640355 0 0 0 5.1 0.3H2.3A1.283659166359277 1.283659166359277 0 0 0 1 1.6V4.5H0.5A0.5016599040944301 0.5016599040944301 0 0 0 0 5V35.4A0.5016599040944301 0.5016599040944301 0 0 0 0.5 35.9H1V38.7A1.283659166359277 1.283659166359277 0 0 0 2.3 40H10.6V39.6H12.8V40H21.2A1.283659166359277 1.283659166359277 0 0 0 22.5 38.7V35.9H23.1A0.5016599040944301 0.5016599040944301 0 0 0 23.6 35.4V5.1A0.5016599040944301 0.5016599040944301 0 0 0 23.1 4.6H22.5V1.6A1.283659166359277 1.283659166359277 0 0 0 21.2 0.4H18.5C18.4 0.1 17.2 0 17 0zM6.2 34.5L3.7 33.8A1.0033198081888601 1.0033198081888601 0 0 1 3.4 33.7A0.2360752489856142 0.2360752489856142 0 0 1 3.3 33.5A0.20656584286241245 0.20656584286241245 0 0 1 3.4 33.3L4.1 32.8A7.657690888970861 7.657690888970861 0 0 1 3.1 30A8.51346366654371 8.51346366654371 0 0 1 4.8 23.5C5.8 24.2 6.5 24.7 6.5 24.7A7.377351530800443 7.377351530800443 0 0 0 5.4 26.9A6.300258207303577 6.300258207303577 0 0 0 6 31.8L6.5 31.5H6.5L6.6 31.5A0.3541128734784213 0.3541128734784213 0 0 1 6.8 31.4A0.17705643673921065 0.17705643673921065 0 0 1 7 31.5A0.6344522316488379 0.6344522316488379 0 0 1 7 32L6.2 34.5zM17.5 31.8H17.5A6.300258207303577 6.300258207303577 0 0 0 18 26.9A7.510143858354851 7.510143858354851 0 0 0 17 24.7L17.1 24.6L18.6 23.5A8.631501291036518 8.631501291036518 0 0 1 20.3 30A7.657690888970861 7.657690888970861 0 0 1 19.3 32.8L19.8 33.1L20 33.2A0.22132054592401326 0.22132054592401326 0 0 1 20.1 33.4A0.26558465510881596 0.26558465510881596 0 0 1 20 33.6A1.0033198081888601 1.0033198081888601 0 0 1 19.7 33.7L17.2 34.5S17.1 34.1 17 33.6S16.6 32.3 16.5 32A0.619697528587237 0.619697528587237 0 0 1 16.5 31.5A0.17705643673921065 0.17705643673921065 0 0 1 16.6 31.4A0.48690520103282936 0.48690520103282936 0 0 1 16.8 31.4L16.8 31.4L17.4 31.7zM11.7 30.6A1.9918849133161198 1.9918849133161198 0 1 1 13.7 28.6A1.9918849133161198 1.9918849133161198 0 0 1 11.7 30.6H11.7z" />
|
horiz-adv-x="23.578015492438215" d=" M17 0H6.4A5.901881224640355 5.901881224640355 0 0 0 5.1 0.3H2.3A1.283659166359277 1.283659166359277 0 0 0 1 1.6V4.5H0.5A0.5016599040944301 0.5016599040944301 0 0 0 0 5V35.4A0.5016599040944301 0.5016599040944301 0 0 0 0.5 35.9H1V38.7A1.283659166359277 1.283659166359277 0 0 0 2.3 40H10.6V39.6H12.8V40H21.2A1.283659166359277 1.283659166359277 0 0 0 22.5 38.7V35.9H23.1A0.5016599040944301 0.5016599040944301 0 0 0 23.6 35.4V5.1A0.5016599040944301 0.5016599040944301 0 0 0 23.1 4.6H22.5V1.6A1.283659166359277 1.283659166359277 0 0 0 21.2 0.4H18.5C18.4 0.1 17.2 0 17 0zM6.2 34.5L3.7 33.8A1.0033198081888601 1.0033198081888601 0 0 1 3.4 33.7A0.2360752489856142 0.2360752489856142 0 0 1 3.3 33.5A0.20656584286241245 0.20656584286241245 0 0 1 3.4 33.3L4.1 32.8A7.657690888970861 7.657690888970861 0 0 1 3.1 30A8.51346366654371 8.51346366654371 0 0 1 4.8 23.5C5.8 24.2 6.5 24.7 6.5 24.7A7.377351530800443 7.377351530800443 0 0 0 5.4 26.9A6.300258207303577 6.300258207303577 0 0 0 6 31.8L6.5 31.5H6.5L6.6 31.5A0.3541128734784213 0.3541128734784213 0 0 1 6.8 31.4A0.17705643673921065 0.17705643673921065 0 0 1 7 31.5A0.6344522316488379 0.6344522316488379 0 0 1 7 32L6.2 34.5zM17.5 31.8H17.5A6.300258207303577 6.300258207303577 0 0 0 18 26.9A7.510143858354851 7.510143858354851 0 0 0 17 24.7L17.1 24.6L18.6 23.5A8.631501291036518 8.631501291036518 0 0 1 20.3 30A7.657690888970861 7.657690888970861 0 0 1 19.3 32.8L19.8 33.1L20 33.2A0.22132054592401326 0.22132054592401326 0 0 1 20.1 33.4A0.26558465510881596 0.26558465510881596 0 0 1 20 33.6A1.0033198081888601 1.0033198081888601 0 0 1 19.7 33.7L17.2 34.5S17.1 34.1 17 33.6S16.6 32.3 16.5 32A0.619697528587237 0.619697528587237 0 0 1 16.5 31.5A0.17705643673921065 0.17705643673921065 0 0 1 16.6 31.4A0.48690520103282936 0.48690520103282936 0 0 1 16.8 31.4L16.8 31.4L17.4 31.7zM11.7 30.6A1.9918849133161198 1.9918849133161198 0 1 1 13.7 28.6A1.9918849133161198 1.9918849133161198 0 0 1 11.7 30.6H11.7z" />
|
||||||
|
<glyph glyph-name="addpackage"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M20 35.7C11.3 35.7 4.3 28.7 4.3 20S11.3 4.3 20 4.3S35.7 11.3 35.7 20S28.7 35.7 20 35.7zM30.4 18.3H21.7V9.6H18.3V18.3H9.6V21.7H18.3V30.4H21.7V21.7H30.4V18.3z" />
|
||||||
|
<glyph glyph-name="brick"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M34.3 0.9H5.7V39.1H34.4V0.9zM10.4 32.7V18.4H29.6V32.7H10.4z" />
|
||||||
|
<glyph glyph-name="controls"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M6.1 33H9.6V5.2H6.1V33z M18.3 33H21.7V5.2H18.3V33z M30.4 33H33.9V5.2H30.4V33z M2.6 15.7H13V7H2.6V15.7z M14.8 31.3H25.2V22.6H14.8V31.3z M27 22.6H37.4V13.9H27V22.6z" />
|
||||||
|
<glyph glyph-name="functions"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M12.2 25.4H9.1C9.1 26.3 9.1 26.5 9.9 26.5C11.5 26.5 12.5 27.2 13.1 28.6C13.8 30.1 14.8 31.5 15.7 33.1C16.5 34.3 18.1 35.3 19.7 35.5C20.7 35.7 21.9 35.3 22.5 34.5C22.8 33.9 22.8 33.4 22.6 32.7C22.3 32.2 21.8 32 21.1 32.2C20.5 32.2 20.2 32.7 20.2 33.3C20.2 33.4 20.2 33.4 20.2 33.6C20.2 33.9 20.4 34.3 20.4 34.6C20 34.6 19.5 34.8 19.2 34.6C18.5 34.3 17.9 33.9 17.4 33.1C16.7 32 16.2 30.6 15.7 29.4C15.3 28.6 15 27.3 14.8 26.5H17.2C17.1 26.1 17.1 25.8 16.9 25.4H14.5C13.9 23.5 13.6 21.9 12.9 20.2C12.2 16.7 10.8 13.4 9.4 10.1C8.7 8.6 7.7 7.3 6.6 6.3C5.8 5.4 4.5 4.9 3.3 4.9C2.6 4.7 1.8 5.1 1.1 5.4C0.7 5.8 0.5 6.5 0.7 7.2C1.1 7.7 1.6 8 2.5 7.9C3 7.9 3.2 7.3 3.2 6.8C3.2 6.6 3 6.5 3 6.5C2.8 6.3 2.8 6.1 2.8 5.9C3 5.9 3.2 5.8 3.5 5.8C4.4 5.8 5.4 6.3 5.9 7.2C6.5 8 7 9.1 7.2 9.9C8.5 15.2 10.1 20.4 11.7 25.4C12.2 25.3 12.2 25.3 12.2 25.4z M32.5 4.7C32.7 4.9 32.7 5.1 32.9 5.3C34.8 6.3 36 8.4 36.4 10.5C37.1 13.9 37.1 17.4 36.2 20.9C35.7 22.8 34.5 24.2 33.1 25.4C32.9 25.6 32.7 25.8 32.7 25.9C36 24.7 39.2 20.6 39.2 15.3C39.3 10.8 36.7 6.5 32.5 4.7z M23.9 25.8C23.9 25.6 23.7 25.4 23.7 25.4C21.8 24.4 20.5 22.3 20.2 20.2C19.5 16.7 19.5 13.3 20.4 9.6C20.9 7.7 22.1 6.3 23.5 5.1C23.7 4.9 23.9 4.9 23.9 4.6C20 6.5 17.4 10.5 17.6 15C17.4 20.7 20.9 24.9 23.9 25.8z M32 12.2C32 12.2 32.2 12.2 32.4 12C32.4 12 32.4 12 32.4 11.9C31.9 11 31.3 10.1 30.3 9.6C29.9 9.3 29.2 9.1 28.5 9.6C28.4 9.8 28.2 9.9 28.2 10.3C27.9 11.3 27.7 12.4 27.5 13.4C27.5 13.6 27.5 13.6 27.3 13.8C27.2 13.4 27 13.1 26.6 12.7C26.1 12 25.6 11 24.7 10.3C24.4 9.9 24 9.6 23.5 9.4C23 9.3 22.5 9.4 21.9 9.9V10.1C21.9 10.5 21.9 10.8 22.3 11C22.5 11.2 22.8 11.2 23.2 11L23.3 10.8C23.9 10.5 24 10.3 24.4 11C25.1 12 25.9 13.4 26.8 14.5C26.8 14.6 26.8 14.8 26.8 15C26.6 15.7 26.5 16.6 26.3 17.3C25.9 18.5 25.4 19 24 19H23.9C23.7 19.2 23.9 19.3 24 19.3C24.7 19.5 25.8 19.7 26.5 19.7C26.6 19.7 26.8 19.7 27 19.5C27.5 18.8 27.9 18.1 28 17.1C28 16.9 28.2 16.6 28.2 16.4C28.4 16.7 28.7 17.3 29.1 17.6C29.6 18.1 30.1 18.8 30.8 19.3C31.2 19.5 31.5 19.7 31.9 19.7C32.4 19.7 32.7 19.3 32.7 18.8V18.6C32.5 18.1 32.2 17.9 31.7 18.1L31.7 18.1C31.5 18.1 31.5 18.1 31.3 18.1C30.8 18.5 30.1 18.3 29.6 17.8L29.6 17.8C29.2 17.3 28.7 16.6 28.4 15.9C28.4 15.7 28.4 15.7 28.4 15.5C28.7 14.3 28.9 12.9 29.2 11.5C29.2 11.3 29.2 11.3 29.4 11.2C29.6 10.6 29.9 10.5 30.3 11C31.3 11.3 31.5 11.9 32 12.2z" />
|
||||||
|
<glyph glyph-name="list"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M11.1 30.4H36.9V27.3H11.1V30.4z M11.1 22.4H36.9V19.3H11.1V22.4z M11.1 14.4H36.9V11.3H11.1V14.4z M5.6 27.3H3.8V33.6H2.4V34.6C3.3 34.6 4 35.1 4.2 36.2H5.6V27.3z M7.7 17.6V16H1.4V16.7C1.4 18.8 2.8 19.7 4 20.3C5.7 21.2 5.7 21.6 5.7 22.1C5.7 22.6 5.4 23.1 4.5 23.1C3.7 23.1 3.1 22.4 3.1 21.6H1.4C1.4 23.1 2.4 24.7 4.5 24.7C6.6 24.7 7.5 23.3 7.5 22.1C7.5 20.3 6.3 19.8 4.9 19C4 18.4 3.3 17.9 3.3 17.4H7.7z M4.5 4.5C2.4 4.5 1.4 5.9 1.2 7.5H3C3 6.6 3.5 6.1 4.5 6.1C5.6 6.1 6.1 6.6 6.1 7.3C6.1 8 5.6 8.5 4.7 8.5H4.2V9.9H4.5C5.6 9.9 5.9 10.4 5.9 11C5.9 11.7 5.4 12 4.7 12C3.8 12 3.3 11.3 3.3 10.6H1.6C1.6 12.2 2.6 13.6 4.5 13.6C6.4 13.6 7.5 12.3 7.5 11.1C7.5 10.4 7.1 9.7 6.3 9.4C7.3 9 7.7 8.2 7.7 7.3C7.8 6.1 6.8 4.5 4.5 4.5z" />
|
||||||
|
<glyph glyph-name="logic"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M2.8 14.1H7.4C10 14.2 12.2 16 13.1 18.6C15 23.1 18.3 31.3 23.7 31.3S29.8 31.3 29.8 31.3V35.8L36.9 28.3L29.8 21.5V26.4H24.9C22.3 25.7 20.2 24 19.4 21.5C17.3 17 15.2 9.4 8.2 9.2C5.1 9.2 3 9.2 3 9.2V14.1z M2.8 31.1V26.2H8.2C8.2 26.2 11.4 26.2 13.1 22.1C13.8 23.8 14.7 25.4 15.7 26.9C15.7 26.9 12.2 30.9 8.4 30.9S2.8 31.1 2.8 31.1z M19.5 18.4C19.5 18.4 21.8 13.9 24.4 13.9H30V18.4L37.3 11.3L30 4.2V9H23.7C23.7 9 20.2 9 16.9 13.4C18 14.9 18.8 16.7 19.5 18.4z" />
|
||||||
|
<glyph glyph-name="loops"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M6.3 12.7C4.5 15.2 2.6 17.4 0.9 20H4.5C4.5 24.2 6.3 28.4 9.2 31.3C11.3 33.4 13.7 34.8 16.7 35.3C21.9 36.6 27.3 35 31.1 31.2C30.3 30.3 29.4 29.4 28.7 28.7C24.2 32.6 19.3 33.3 14.1 30.5C10.3 28.4 8.2 24.4 8.2 20.2H11.8C9.7 17.6 7.8 15 6.3 12.7z M32.2 20H28.5C30.4 22.5 32.2 24.7 33.9 27.3C35.8 24.9 37.6 22.6 39.3 20H35.6C35.6 15.7 33.7 11.5 30.6 8.6C28.5 6.6 26.1 5.3 23.3 4.7C18.1 3.5 12.7 5.1 8.9 8.9L11.3 11.3C15.6 7.5 20.7 6.6 25.9 9.6C29.9 11.7 32.2 15.7 32.2 20z" />
|
||||||
|
<glyph glyph-name="math"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M15.2 5.3C14.9 4.9 14.2 4.2 13.8 3.9L9.3 8.4C7.6 6.7 6.2 5.3 4.8 3.9C4.4 4.2 3.8 4.9 3.4 5.3L7.9 9.8C6.2 11.5 4.8 12.9 3.4 14.3C3.8 14.7 4.4 15.4 4.8 15.7L9.3 11.2L13.8 15.7C14.2 15.4 14.9 14.7 15.2 14.3L10.7 9.8C12.1 8.2 13.7 6.7 15.2 5.3z M1.5 28V30H7.9V36.4C8.6 36.4 9.1 36.4 9.8 36.4V30H16.3V28H9.8V21.6H7.8V28H1.5z M38.4 10.7H22V14.1H38.4V10.7z M38.4 7.2V3.7H22V7.2H38.4z M38.4 31V27.5H22V31H38.4z" />
|
||||||
|
<glyph glyph-name="motors"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M28.9 25.8C27.5 24.4 25.9 22.9 24.5 21.5H35.7V32.6L32.2 29.1C29.6 32.3 25.9 34.3 21.8 34.9C18.3 35.4 14.6 34.5 11.7 32.6C4.2 28.1 1.9 18.3 6.5 10.9S20.7 1.1 28.2 5.6C30.8 7.2 32.7 9.5 34.1 12.1C32.7 12.6 31.3 13.3 29.9 13.8C28.5 11 25.9 9 23 8.1C20.7 7.4 18.3 7.6 16 8.4C10.3 10.7 7.3 17.1 9.4 22.9C10.6 26.3 13.6 29 17.1 29.8C21.6 31.2 26.3 29.5 28.9 25.8z M16.7 19C16.7 17.1 18.3 15.7 20 15.7S23.3 17.3 23.3 19C23.3 21 21.8 22.3 20 22.3C18.1 22.5 16.7 21 16.7 19C16.7 19 16.7 19 16.7 19z" />
|
||||||
|
<glyph glyph-name="music"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M24.2 17.7C27.1 17.2 29.9 15.7 31.7 13.2C32.5 13.2 33.4 13.2 33.4 13.2S36 20.9 30.3 26.3S13.4 31.7 9.2 26.3C6.3 22.6 5.2 17.6 6.8 13.2C7.3 13.2 7.7 13.2 8.2 13.2C8.2 13.2 11.1 17.6 15.8 17.7C15.7 10.1 15.7 3.5 15.7 3.5C12.3 4.2 9.6 6.3 8 9.4C4.5 10.1 1.7 13.2 1.7 17C1.7 28.3 10.3 34.8 20 34.8S38.8 27.3 38.1 17C37.7 9.9 31.8 9.4 31.8 9.4C30.4 6.3 27.7 4 24.3 3.5C24.2 11.3 24.2 17.7 24.2 17.7z" />
|
||||||
|
<glyph glyph-name="sensors"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M20 36.9C10.6 36.9 3 29.2 3 19.8C3 10.4 10.6 2.8 20 2.8S37 10.4 37 19.8C36.9 29.4 29.4 36.9 20 36.9zM20 8.2C13.4 8.2 8.2 13.6 8.2 20S13.6 31.8 20 31.8S31.8 26.4 31.8 20S26.6 8.2 20 8.2z M13.2 20C13.2 16.3 16.3 13.2 20 13.2C23.7 13.2 26.8 16.3 26.8 20C26.8 23.7 23.7 26.8 20 26.8C16.3 26.8 13.2 23.7 13.2 20z" />
|
||||||
|
<glyph glyph-name="text"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M23.1 30.6V2.8H16.5V30.6H7.7V36.7H32.3V30.6H23.1z" />
|
||||||
|
<glyph glyph-name="variables"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M36.8 12V7.8H3.4V12H36.8z M36.8 22.1V17.9H3.4V22.1H36.8z M36.7 32.2V28H3.3V32.2H36.7z" />
|
||||||
|
<glyph glyph-name="advancedcollapsed"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M39.7 28.2L36.2 31.5L20 15.3L3.8 31.5L0.3 28.2L18.3 10.3L18.3 10.3L20 8.5L20.5 9L20.5 9z" />
|
||||||
|
<glyph glyph-name="advancedexpanded"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M39.3 12L21.7 29.6L21.7 29.6L20 31.3L19.5 30.8L19.5 30.8L0.7 12L4 8.7L20 24.7L36 8.7z" />
|
||||||
|
<glyph glyph-name="cancel"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M33 29.6L29.4 33.2L20.2 24L11 33.2L7.3 29.6L16.5 20.3L7.3 11.1L11 7.3L20.2 16.5L29.4 7.3L33 11.1L23.8 20.3z" />
|
||||||
|
<glyph glyph-name="check"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M33.7 32.9L15.3 14.4L7.5 22.3L3.8 18.4L11.7 10.8L11.7 10.8L15.3 7.1L37.4 29.2z" />
|
||||||
|
<glyph glyph-name="download"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M5.2 15.7H36.5V1.7H5.2V15.7z M28.5 24.2L26.1 26.6L22.6 23.1L22.6 36.5L19.1 36.5L19.1 23.5L16 26.6L13.6 24.2L20.9 16.7L21 16.9L21.2 16.7z" />
|
||||||
|
<glyph glyph-name="save"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M25 34.5C25 33.6 25 32.8 25 31.9C25 31 24.7 30.9 24 30.9C23.5 30.9 22.8 30.9 22.4 30.9C22.1 30.9 21.4 31 21.4 31.7V31.9V36.9C21.4 37.3 21.6 37.8 22.3 38C22.3 38 22.3 38 22.4 38C23 38 23.7 38 24.2 38C24.7 38 25.2 37.6 25.2 37.1C25.2 37.1 25.2 37.1 25.2 36.9C25 36.3 25 35.2 25 34.5z M37.6 31.2C35.8 32.9 34.3 34.5 32.5 36.3C31 37.8 31 37.8 28.5 37.8C27.5 37.8 27.3 37.6 27.3 36.6V28.4C27.3 27.4 27.1 27.2 26.1 27.2H14.3C13.2 27.2 13 27.4 13 28.4V36.4C13 37.6 12.9 37.8 11.7 37.8H3.8C2.6 37.8 2.4 37.6 2.4 36.4V19.9C2.4 14.3 2.4 8.9 2.4 3.2C2.4 2 2.6 1.8 3.7 1.8H36.9C37.9 1.8 38.1 2.2 38.1 3.2V29.6C38.3 30.5 37.9 30.9 37.6 31.2zM33.7 6.7H7.1V23H33.7V6.7z" />
|
||||||
|
<glyph glyph-name="blocks"
|
||||||
|
unicode=""
|
||||||
|
horiz-adv-x="40" d=" M10.9 23H39V16.9H10.9V23z M39.2 27.1L39.2 33L0.9 33L0.9 31.1L0.9 27.1L0.9 12.9L0.9 7L39.2 7L39.2 12.9L6.9 12.9L6.9 27.1z" />
|
||||||
</font>
|
</font>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 15 KiB |
BIN
docs/static/fonts/icons/iconfont.ttf
vendored
BIN
docs/static/fonts/icons/iconfont.woff
vendored
BIN
docs/static/fonts/icons/iconfont.woff2
vendored
@ -1,94 +0,0 @@
|
|||||||
```typescript
|
|
||||||
let errors: string[] = [];
|
|
||||||
let tachoB = 0;
|
|
||||||
let tachoC = 0;
|
|
||||||
|
|
||||||
function assert(name: string, condition: boolean) {
|
|
||||||
if (!condition) {
|
|
||||||
errors.push(name)
|
|
||||||
brick.print("error:" + name, 0, 60)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertClose(name: string, expected: number, actual: number, tolerance = 5) {
|
|
||||||
const diff = Math.abs(expected - actual);
|
|
||||||
assert(name + ` ${expected}vs${actual}`, diff < tolerance);
|
|
||||||
}
|
|
||||||
|
|
||||||
function state(name: string, motor: motors.SingleMotor, line: number) {
|
|
||||||
brick.print(`${name}: ${motor.speed()}%,${motor.angle()}deg`, 0, 12 * line)
|
|
||||||
}
|
|
||||||
|
|
||||||
function test(name: string, f: () => void, check?: () => void) {
|
|
||||||
motors.stopAllMotors();
|
|
||||||
motors.largeB.clearCount()
|
|
||||||
motors.largeC.clearCount()
|
|
||||||
motors.largeB.setBrake(false)
|
|
||||||
motors.largeC.setBrake(false)
|
|
||||||
motors.largeB.setReversed(false);
|
|
||||||
motors.largeC.setReversed(false);
|
|
||||||
loops.pause(500);
|
|
||||||
tachoB = motors.largeB.angle()
|
|
||||||
tachoC = motors.largeC.angle()
|
|
||||||
brick.clearScreen()
|
|
||||||
brick.print(name, 0, 0)
|
|
||||||
state("B", motors.largeB, 1)
|
|
||||||
state("C", motors.largeC, 2)
|
|
||||||
f();
|
|
||||||
loops.pause(3000);
|
|
||||||
state("B", motors.largeB, 3)
|
|
||||||
state("C", motors.largeC, 4)
|
|
||||||
if (check)
|
|
||||||
check()
|
|
||||||
motors.stopAllMotors();
|
|
||||||
loops.pause(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
brick.buttonLeft.onEvent(ButtonEvent.Click, function () {
|
|
||||||
test("lgBC set speed 25", () => {
|
|
||||||
motors.largeBC.setSpeed(25)
|
|
||||||
}, () => {
|
|
||||||
assertClose("speedB", 25, motors.largeB.speed());
|
|
||||||
assertClose("speedC", 25, motors.largeC.speed());
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
|
||||||
test("lgB set speed 10", () => {
|
|
||||||
motors.largeB.setSpeed(10)
|
|
||||||
}, () => assertClose("speedB", 10, motors.largeB.speed()));
|
|
||||||
test("lgB set speed 25 (reversed)", () => {
|
|
||||||
motors.largeB.setReversed(true)
|
|
||||||
motors.largeB.setSpeed(25)
|
|
||||||
}, () => assertClose("speedB", -25, motors.largeB.speed()));
|
|
||||||
test("lgBC set speed 5", () => {
|
|
||||||
motors.largeBC.setSpeed(5)
|
|
||||||
}, () => {
|
|
||||||
assertClose("speedB", 5, motors.largeB.speed());
|
|
||||||
assertClose("speedC", 5, motors.largeC.speed());
|
|
||||||
});
|
|
||||||
test("lgBC steer 50% 2x", () => {
|
|
||||||
motors.largeBC.setBrake(true)
|
|
||||||
motors.largeBC.steer(50, 50, 2, MoveUnit.Rotations)
|
|
||||||
}, () => assertClose("largeB", 720, motors.largeB.angle()));
|
|
||||||
test("lgBC steer 50% 500deg", () => {
|
|
||||||
motors.largeBC.setBrake(true)
|
|
||||||
motors.largeBC.steer(50, 50, 500, MoveUnit.Degrees)
|
|
||||||
}, () => assertClose("largeB", 500, motors.largeB.angle()));
|
|
||||||
test("lgBC steer 50% 2s", () => {
|
|
||||||
motors.largeBC.setBrake(true)
|
|
||||||
motors.largeBC.steer(50, 50, 2000, MoveUnit.MilliSeconds)
|
|
||||||
})
|
|
||||||
test("lgBC tank 50% 720deg", () => {
|
|
||||||
motors.largeBC.setBrake(true)
|
|
||||||
motors.largeBC.tank(50, 50, 720, MoveUnit.Degrees)
|
|
||||||
}, () => assertClose("largeB", 720, motors.largeB.angle()));
|
|
||||||
|
|
||||||
brick.clearScreen()
|
|
||||||
brick.print(`${errors.length} errors`, 0, 0)
|
|
||||||
let l = 1;
|
|
||||||
for (const error of errors)
|
|
||||||
brick.print(`error: ${error}`, 0, l++ * 12)
|
|
||||||
})
|
|
||||||
|
|
||||||
```
|
|
133
editor/deploy.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/>
|
||||||
|
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||||
|
|
||||||
|
import UF2 = pxtc.UF2;
|
||||||
|
|
||||||
|
export let ev3: pxt.editor.Ev3Wrapper
|
||||||
|
|
||||||
|
export function debug() {
|
||||||
|
return initAsync()
|
||||||
|
.then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v))))
|
||||||
|
}
|
||||||
|
|
||||||
|
function hf2Async() {
|
||||||
|
return pxt.HF2.mkPacketIOAsync()
|
||||||
|
.then(h => {
|
||||||
|
let w = new pxt.editor.Ev3Wrapper(h)
|
||||||
|
ev3 = w
|
||||||
|
return w.reconnectAsync(true)
|
||||||
|
.then(() => w)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let noHID = false
|
||||||
|
|
||||||
|
let initPromise: Promise<pxt.editor.Ev3Wrapper>
|
||||||
|
export function initAsync() {
|
||||||
|
if (initPromise)
|
||||||
|
return initPromise
|
||||||
|
|
||||||
|
let canHID = false
|
||||||
|
if (pxt.U.isNodeJS) {
|
||||||
|
canHID = true
|
||||||
|
} else {
|
||||||
|
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
|
||||||
|
if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload)
|
||||||
|
canHID = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noHID)
|
||||||
|
canHID = false
|
||||||
|
|
||||||
|
if (canHID) {
|
||||||
|
initPromise = hf2Async()
|
||||||
|
.catch(err => {
|
||||||
|
initPromise = null
|
||||||
|
noHID = true
|
||||||
|
return Promise.reject(err)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
noHID = true
|
||||||
|
initPromise = Promise.reject(new Error("no HID"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return initPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
// this comes from aux/pxt.lms
|
||||||
|
const rbfTemplate = `
|
||||||
|
4c45474f580000006d000100000000001c000000000000000e000000821b038405018130813e8053
|
||||||
|
74617274696e672e2e2e0084006080XX00448581644886488405018130813e80427965210084000a
|
||||||
|
`
|
||||||
|
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
||||||
|
let w: pxt.editor.Ev3Wrapper
|
||||||
|
|
||||||
|
let filename = resp.downloadFileBaseName || "pxt"
|
||||||
|
filename = filename.replace(/^lego-/, "")
|
||||||
|
|
||||||
|
let fspath = "../prjs/BrkProg_SAVE/"
|
||||||
|
|
||||||
|
let elfPath = fspath + filename + ".elf"
|
||||||
|
let rbfPath = fspath + filename + ".rbf"
|
||||||
|
|
||||||
|
let rbfHex = rbfTemplate
|
||||||
|
.replace(/\s+/g, "")
|
||||||
|
.replace("XX", pxt.U.toHex(pxt.U.stringToUint8Array(elfPath)))
|
||||||
|
let rbfBIN = pxt.U.fromHex(rbfHex)
|
||||||
|
pxt.HF2.write16(rbfBIN, 4, rbfBIN.length)
|
||||||
|
|
||||||
|
let origElfUF2 = UF2.parseFile(pxt.U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
|
||||||
|
|
||||||
|
let mkFile = (ext: string, data: Uint8Array = null) => {
|
||||||
|
let f = UF2.newBlockFile()
|
||||||
|
f.filename = "Projects/" + filename + ext
|
||||||
|
if (data)
|
||||||
|
UF2.writeBytes(f, 0, data)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
let elfUF2 = mkFile(".elf")
|
||||||
|
for (let b of origElfUF2) {
|
||||||
|
UF2.writeBytes(elfUF2, b.targetAddr, b.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = UF2.concatFiles([elfUF2, mkFile(".rbf", rbfBIN)])
|
||||||
|
let data = UF2.serializeFile(r)
|
||||||
|
|
||||||
|
resp.outfiles[pxtc.BINARY_UF2] = btoa(data)
|
||||||
|
|
||||||
|
let saveUF2Async = () => {
|
||||||
|
if (isCli || !pxt.commands.saveOnlyAsync) {
|
||||||
|
return Promise.resolve()
|
||||||
|
} else {
|
||||||
|
return pxt.commands.saveOnlyAsync(resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noHID) return saveUF2Async()
|
||||||
|
|
||||||
|
return initAsync()
|
||||||
|
.then(w_ => {
|
||||||
|
w = w_
|
||||||
|
if (w.isStreaming)
|
||||||
|
pxt.U.userError("please stop the program first")
|
||||||
|
return w.stopAsync()
|
||||||
|
})
|
||||||
|
.then(() => w.rmAsync(elfPath))
|
||||||
|
.then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
|
||||||
|
.then(() => w.flashAsync(rbfPath, rbfBIN))
|
||||||
|
.then(() => w.runAsync(rbfPath))
|
||||||
|
.then(() => {
|
||||||
|
if (isCli)
|
||||||
|
return w.disconnectAsync()
|
||||||
|
else
|
||||||
|
return Promise.resolve()
|
||||||
|
//return Promise.delay(1000).then(() => w.dmesgAsync())
|
||||||
|
}).catch(e => {
|
||||||
|
// if we failed to initalize, retry
|
||||||
|
if (noHID)
|
||||||
|
return saveUF2Async()
|
||||||
|
else
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
}
|
@ -1,152 +1,120 @@
|
|||||||
/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts" />
|
/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/>
|
||||||
|
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||||
|
|
||||||
|
import { deployCoreAsync, initAsync } from "./deploy";
|
||||||
|
import { FieldPorts } from "./field_ports";
|
||||||
|
import { FieldImages } from "./field_images";
|
||||||
|
|
||||||
|
pxt.editor.initExtensionsAsync = function(opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
|
||||||
|
pxt.debug('loading pxt-ev3 target extensions...')
|
||||||
|
updateBlocklyShape();
|
||||||
|
const res: pxt.editor.ExtensionResult = {
|
||||||
|
fieldEditors: [{
|
||||||
|
selector: "ports",
|
||||||
|
editor: FieldPorts
|
||||||
|
}, {
|
||||||
|
selector: "images",
|
||||||
|
editor: FieldImages
|
||||||
|
}],
|
||||||
|
deployCoreAsync
|
||||||
|
};
|
||||||
|
initAsync().catch(e => {
|
||||||
|
// probably no HID - we'll try this again upon deployment
|
||||||
|
})
|
||||||
|
return Promise.resolve<pxt.editor.ExtensionResult>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the shape of Blockly blocks with square corners
|
||||||
|
*/
|
||||||
|
function updateBlocklyShape() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounded corner radius.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).CORNER_RADIUS = 0 * (Blockly.BlockSvg as any).GRID_UNIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inner space between edge of statement input and notch.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).STATEMENT_INPUT_INNER_SPACE = 3 * (Blockly.BlockSvg as any).GRID_UNIT;
|
||||||
|
/**
|
||||||
|
* SVG path for drawing next/previous notch from left to right.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).NOTCH_PATH_LEFT = (
|
||||||
|
'l 8,8 ' +
|
||||||
|
'h 16 ' +
|
||||||
|
'l 8,-8 '
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing next/previous notch from right to left.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).NOTCH_PATH_RIGHT = (
|
||||||
|
'l -8,8 ' +
|
||||||
|
'h -16 ' +
|
||||||
|
'l -8,-8 '
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG start point for drawing the top-left corner.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).TOP_LEFT_CORNER_START =
|
||||||
|
'm 0,' + 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing the rounded top-left corner.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).TOP_LEFT_CORNER =
|
||||||
|
'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0 ';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing the rounded top-right corner.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).TOP_RIGHT_CORNER =
|
||||||
|
'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing the rounded bottom-right corner.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).BOTTOM_RIGHT_CORNER =
|
||||||
|
'l 0,' + (Blockly.BlockSvg as any).CORNER_RADIUS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing the rounded bottom-left corner.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).BOTTOM_LEFT_CORNER =
|
||||||
|
'l -' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing the top-left corner of a statement input.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).INNER_TOP_LEFT_CORNER =
|
||||||
|
'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',-' + 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVG path for drawing the bottom-left corner of a statement input.
|
||||||
|
* Includes the rounded inside corner.
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
(Blockly.BlockSvg as any).INNER_BOTTOM_LEFT_CORNER =
|
||||||
|
'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS * 2 +
|
||||||
|
'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',' + 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// When require()d from node, bind the global pxt namespace
|
// When require()d from node, bind the global pxt namespace
|
||||||
namespace pxt {
|
// namespace pxt {
|
||||||
export const dummyExport = 1;
|
// export const dummyExport = 1;
|
||||||
}
|
// }
|
||||||
eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt")
|
// eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt")
|
||||||
|
|
||||||
namespace pxt.editor {
|
|
||||||
import UF2 = pxtc.UF2;
|
|
||||||
|
|
||||||
export let ev3: Ev3Wrapper
|
|
||||||
|
|
||||||
export function debug() {
|
|
||||||
return initAsync()
|
|
||||||
.then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// this comes from aux/pxt.lms
|
|
||||||
const rbfTemplate = `
|
|
||||||
4c45474f580000006d000100000000001c000000000000000e000000821b038405018130813e8053
|
|
||||||
74617274696e672e2e2e0084006080XX00448581644886488405018130813e80427965210084000a
|
|
||||||
`
|
|
||||||
|
|
||||||
function hf2Async() {
|
|
||||||
return pxt.HF2.mkPacketIOAsync()
|
|
||||||
.then(h => {
|
|
||||||
let w = new Ev3Wrapper(h)
|
|
||||||
ev3 = w
|
|
||||||
return w.reconnectAsync(true)
|
|
||||||
.then(() => w)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let noHID = false
|
|
||||||
|
|
||||||
let initPromise: Promise<Ev3Wrapper>
|
|
||||||
function initAsync() {
|
|
||||||
if (initPromise)
|
|
||||||
return initPromise
|
|
||||||
|
|
||||||
let canHID = false
|
|
||||||
if (U.isNodeJS) {
|
|
||||||
canHID = true
|
|
||||||
} else {
|
|
||||||
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
|
|
||||||
if (Cloud.isLocalHost() && Cloud.localToken && !forceHexDownload)
|
|
||||||
canHID = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noHID)
|
|
||||||
canHID = false
|
|
||||||
|
|
||||||
if (canHID) {
|
|
||||||
initPromise = hf2Async()
|
|
||||||
.catch(err => {
|
|
||||||
initPromise = null
|
|
||||||
noHID = true
|
|
||||||
return Promise.reject(err)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
noHID = true
|
|
||||||
initPromise = Promise.reject(new Error("no HID"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return initPromise
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
|
||||||
let w: Ev3Wrapper
|
|
||||||
|
|
||||||
let filename = resp.downloadFileBaseName || "pxt"
|
|
||||||
filename = filename.replace(/^lego-/, "")
|
|
||||||
|
|
||||||
let fspath = "../prjs/BrkProg_SAVE/"
|
|
||||||
|
|
||||||
let elfPath = fspath + filename + ".elf"
|
|
||||||
let rbfPath = fspath + filename + ".rbf"
|
|
||||||
|
|
||||||
let rbfHex = rbfTemplate
|
|
||||||
.replace(/\s+/g, "")
|
|
||||||
.replace("XX", U.toHex(U.stringToUint8Array(elfPath)))
|
|
||||||
let rbfBIN = U.fromHex(rbfHex)
|
|
||||||
HF2.write16(rbfBIN, 4, rbfBIN.length)
|
|
||||||
|
|
||||||
let origElfUF2 = UF2.parseFile(U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
|
|
||||||
|
|
||||||
let mkFile = (ext: string, data: Uint8Array = null) => {
|
|
||||||
let f = UF2.newBlockFile()
|
|
||||||
f.filename = "Projects/" + filename + ext
|
|
||||||
if (data)
|
|
||||||
UF2.writeBytes(f, 0, data)
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
let elfUF2 = mkFile(".elf")
|
|
||||||
for (let b of origElfUF2) {
|
|
||||||
UF2.writeBytes(elfUF2, b.targetAddr, b.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = UF2.concatFiles([elfUF2, mkFile(".rbf", rbfBIN)])
|
|
||||||
let data = UF2.serializeFile(r)
|
|
||||||
|
|
||||||
resp.outfiles[pxtc.BINARY_UF2] = btoa(data)
|
|
||||||
|
|
||||||
let saveUF2Async = () => {
|
|
||||||
if (isCli || !pxt.commands.saveOnlyAsync) {
|
|
||||||
return Promise.resolve()
|
|
||||||
} else {
|
|
||||||
return pxt.commands.saveOnlyAsync(resp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noHID) return saveUF2Async()
|
|
||||||
|
|
||||||
return initAsync()
|
|
||||||
.then(w_ => {
|
|
||||||
w = w_
|
|
||||||
if (w.isStreaming)
|
|
||||||
U.userError("please stop the program first")
|
|
||||||
return w.stopAsync()
|
|
||||||
})
|
|
||||||
.then(() => w.rmAsync(elfPath))
|
|
||||||
.then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
|
|
||||||
.then(() => w.flashAsync(rbfPath, rbfBIN))
|
|
||||||
.then(() => w.runAsync(rbfPath))
|
|
||||||
.then(() => {
|
|
||||||
if (isCli)
|
|
||||||
return w.disconnectAsync()
|
|
||||||
else
|
|
||||||
return Promise.resolve()
|
|
||||||
//return Promise.delay(1000).then(() => w.dmesgAsync())
|
|
||||||
}).catch(e => {
|
|
||||||
// if we failed to initalize, retry
|
|
||||||
if (noHID)
|
|
||||||
return saveUF2Async()
|
|
||||||
else
|
|
||||||
return Promise.reject(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
|
|
||||||
pxt.debug('loading pxt-ev3 target extensions...')
|
|
||||||
const res: pxt.editor.ExtensionResult = {
|
|
||||||
deployCoreAsync,
|
|
||||||
};
|
|
||||||
initAsync().catch(e => {
|
|
||||||
// probably no HID - we'll try this again upon deployment
|
|
||||||
})
|
|
||||||
return Promise.resolve<pxt.editor.ExtensionResult>(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
114
editor/field_images.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
|
||||||
|
/// <reference path="../node_modules/pxt-core/built/pxtblocks.d.ts"/>
|
||||||
|
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||||
|
|
||||||
|
export interface FieldImagesOptions extends pxtblockly.FieldImageDropdownOptions {
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FieldImages extends pxtblockly.FieldImageDropdown implements Blockly.FieldCustom {
|
||||||
|
public isFieldCustom_ = true;
|
||||||
|
|
||||||
|
constructor(text: string, options: FieldImagesOptions, validator?: Function) {
|
||||||
|
super(text, options, validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a dropdown menu under the text.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
public showEditor_() {
|
||||||
|
// If there is an existing drop-down we own, this is a request to hide the drop-down.
|
||||||
|
if (Blockly.DropDownDiv.hideIfOwner(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If there is an existing drop-down someone else owns, hide it immediately and clear it.
|
||||||
|
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||||
|
Blockly.DropDownDiv.clearContent();
|
||||||
|
// Populate the drop-down with the icons for this field.
|
||||||
|
let dropdownDiv = Blockly.DropDownDiv.getContentDiv();
|
||||||
|
let contentDiv = document.createElement('div');
|
||||||
|
// Accessibility properties
|
||||||
|
contentDiv.setAttribute('role', 'menu');
|
||||||
|
contentDiv.setAttribute('aria-haspopup', 'true');
|
||||||
|
const options = this.getOptions();
|
||||||
|
for (let i = 0, option: any; option = options[i]; i++) {
|
||||||
|
let content = (options[i] as any)[0]; // Human-readable text or image.
|
||||||
|
const value = (options[i] as any)[1]; // Language-neutral value.
|
||||||
|
// Icons with the type property placeholder take up space but don't have any functionality
|
||||||
|
// Use for special-case layouts
|
||||||
|
if (content.type == 'placeholder') {
|
||||||
|
let placeholder = document.createElement('span');
|
||||||
|
placeholder.setAttribute('class', 'blocklyDropDownPlaceholder');
|
||||||
|
placeholder.style.width = content.width + 'px';
|
||||||
|
placeholder.style.height = content.height + 'px';
|
||||||
|
contentDiv.appendChild(placeholder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let button = document.createElement('button');
|
||||||
|
button.setAttribute('id', ':' + i); // For aria-activedescendant
|
||||||
|
button.setAttribute('role', 'menuitem');
|
||||||
|
button.setAttribute('class', 'blocklyDropDownButton');
|
||||||
|
button.title = content.alt;
|
||||||
|
if ((this as any).columns_) {
|
||||||
|
button.style.width = (((this as any).width_ / (this as any).columns_) - 8) + 'px';
|
||||||
|
//button.style.height = ((this.width_ / this.columns_) - 8) + 'px';
|
||||||
|
} else {
|
||||||
|
button.style.width = content.width + 'px';
|
||||||
|
button.style.height = content.height + 'px';
|
||||||
|
}
|
||||||
|
let backgroundColor = this.sourceBlock_.getColour();
|
||||||
|
if (value == this.getValue()) {
|
||||||
|
// This icon is selected, show it in a different colour
|
||||||
|
backgroundColor = this.sourceBlock_.getColourTertiary();
|
||||||
|
button.setAttribute('aria-selected', 'true');
|
||||||
|
}
|
||||||
|
button.style.backgroundColor = backgroundColor;
|
||||||
|
button.style.borderColor = this.sourceBlock_.getColourTertiary();
|
||||||
|
Blockly.bindEvent_(button, 'click', this, (this as any).buttonClick_);
|
||||||
|
Blockly.bindEvent_(button, 'mouseup', this, (this as any).buttonClick_);
|
||||||
|
// These are applied manually instead of using the :hover pseudoclass
|
||||||
|
// because Android has a bad long press "helper" menu and green highlight
|
||||||
|
// that we must prevent with ontouchstart preventDefault
|
||||||
|
Blockly.bindEvent_(button, 'mousedown', button, function (e) {
|
||||||
|
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
Blockly.bindEvent_(button, 'mouseover', button, function () {
|
||||||
|
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
|
||||||
|
contentDiv.setAttribute('aria-activedescendant', this.id);
|
||||||
|
});
|
||||||
|
Blockly.bindEvent_(button, 'mouseout', button, function () {
|
||||||
|
this.setAttribute('class', 'blocklyDropDownButton');
|
||||||
|
contentDiv.removeAttribute('aria-activedescendant');
|
||||||
|
});
|
||||||
|
let buttonImg = document.createElement('img');
|
||||||
|
buttonImg.src = content.src;
|
||||||
|
//buttonImg.alt = icon.alt;
|
||||||
|
// Upon click/touch, we will be able to get the clicked element as e.target
|
||||||
|
// Store a data attribute on all possible click targets so we can match it to the icon.
|
||||||
|
button.setAttribute('data-value', value);
|
||||||
|
buttonImg.setAttribute('data-value', value);
|
||||||
|
button.appendChild(buttonImg);
|
||||||
|
contentDiv.appendChild(button);
|
||||||
|
}
|
||||||
|
contentDiv.style.width = (this as any).width_ + 'px';
|
||||||
|
dropdownDiv.appendChild(contentDiv);
|
||||||
|
|
||||||
|
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
|
||||||
|
|
||||||
|
// Calculate positioning based on the field position.
|
||||||
|
var scale = this.sourceBlock_.workspace.scale;
|
||||||
|
var bBox = { width: this.size_.width, height: this.size_.height };
|
||||||
|
bBox.width *= scale;
|
||||||
|
bBox.height *= scale;
|
||||||
|
var position = this.fieldGroup_.getBoundingClientRect();
|
||||||
|
var primaryX = position.left + bBox.width / 2;
|
||||||
|
var primaryY = position.top + bBox.height;
|
||||||
|
var secondaryX = primaryX;
|
||||||
|
var secondaryY = position.top;
|
||||||
|
// Set bounds to workspace; show the drop-down.
|
||||||
|
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
|
||||||
|
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
|
||||||
|
(this as any).onHide_.bind(this));
|
||||||
|
}
|
||||||
|
}
|
147
editor/field_ports.ts
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
|
||||||
|
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||||
|
|
||||||
|
export interface FieldPortsOptions extends Blockly.FieldCustomDropdownOptions {
|
||||||
|
columns?: string;
|
||||||
|
width?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FieldPorts extends Blockly.FieldDropdown implements Blockly.FieldCustom {
|
||||||
|
public isFieldCustom_ = true;
|
||||||
|
|
||||||
|
// Width in pixels
|
||||||
|
private width_: number;
|
||||||
|
|
||||||
|
// Columns in grid
|
||||||
|
private columns_: number;
|
||||||
|
|
||||||
|
private savedPrimary_: string;
|
||||||
|
|
||||||
|
constructor(text: string, options: FieldPortsOptions, validator?: Function) {
|
||||||
|
super(options.data);
|
||||||
|
|
||||||
|
this.columns_ = parseInt(options.columns) || 4;
|
||||||
|
this.width_ = parseInt(options.width) || 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a dropdown menu under the text.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
public showEditor_() {
|
||||||
|
// If there is an existing drop-down we own, this is a request to hide the drop-down.
|
||||||
|
if (Blockly.DropDownDiv.hideIfOwner(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If there is an existing drop-down someone else owns, hide it immediately and clear it.
|
||||||
|
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||||
|
Blockly.DropDownDiv.clearContent();
|
||||||
|
// Populate the drop-down with the icons for this field.
|
||||||
|
let dropdownDiv = Blockly.DropDownDiv.getContentDiv();
|
||||||
|
let contentDiv = document.createElement('div');
|
||||||
|
// Accessibility properties
|
||||||
|
contentDiv.setAttribute('role', 'menu');
|
||||||
|
contentDiv.setAttribute('aria-haspopup', 'true');
|
||||||
|
const options = this.getOptions();
|
||||||
|
for (let i = 0, option: any; option = options[i]; i++) {
|
||||||
|
let content = (options[i] as any)[0]; // Human-readable text or image.
|
||||||
|
const value = (options[i] as any)[1]; // Language-neutral value.
|
||||||
|
// Icons with the type property placeholder take up space but don't have any functionality
|
||||||
|
// Use for special-case layouts
|
||||||
|
if (content.type == 'placeholder') {
|
||||||
|
let placeholder = document.createElement('span');
|
||||||
|
placeholder.setAttribute('class', 'blocklyDropDownPlaceholder');
|
||||||
|
placeholder.style.width = content.width + 'px';
|
||||||
|
placeholder.style.height = content.height + 'px';
|
||||||
|
contentDiv.appendChild(placeholder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let button = document.createElement('button');
|
||||||
|
button.setAttribute('id', ':' + i); // For aria-activedescendant
|
||||||
|
button.setAttribute('role', 'menuitem');
|
||||||
|
button.setAttribute('class', 'blocklyDropDownButton');
|
||||||
|
button.title = content.alt;
|
||||||
|
if (this.columns_) {
|
||||||
|
button.style.width = ((this.width_ / this.columns_) - 8) + 'px';
|
||||||
|
button.style.height = ((this.width_ / this.columns_) - 8) + 'px';
|
||||||
|
} else {
|
||||||
|
button.style.width = content.width + 'px';
|
||||||
|
button.style.height = content.height + 'px';
|
||||||
|
}
|
||||||
|
let backgroundColor = this.sourceBlock_.getColour();
|
||||||
|
if (value == this.getValue()) {
|
||||||
|
// This icon is selected, show it in a different colour
|
||||||
|
backgroundColor = this.sourceBlock_.getColourTertiary();
|
||||||
|
button.setAttribute('aria-selected', 'true');
|
||||||
|
}
|
||||||
|
button.style.backgroundColor = backgroundColor;
|
||||||
|
button.style.borderColor = this.sourceBlock_.getColourTertiary();
|
||||||
|
Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
|
||||||
|
Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
|
||||||
|
// These are applied manually instead of using the :hover pseudoclass
|
||||||
|
// because Android has a bad long press "helper" menu and green highlight
|
||||||
|
// that we must prevent with ontouchstart preventDefault
|
||||||
|
Blockly.bindEvent_(button, 'mousedown', button, function (e) {
|
||||||
|
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
Blockly.bindEvent_(button, 'mouseover', button, function () {
|
||||||
|
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
|
||||||
|
contentDiv.setAttribute('aria-activedescendant', this.id);
|
||||||
|
});
|
||||||
|
Blockly.bindEvent_(button, 'mouseout', button, function () {
|
||||||
|
this.setAttribute('class', 'blocklyDropDownButton');
|
||||||
|
contentDiv.removeAttribute('aria-activedescendant');
|
||||||
|
});
|
||||||
|
let buttonImg = document.createElement('img');
|
||||||
|
buttonImg.src = content.src;
|
||||||
|
//buttonImg.alt = icon.alt;
|
||||||
|
// Upon click/touch, we will be able to get the clicked element as e.target
|
||||||
|
// Store a data attribute on all possible click targets so we can match it to the icon.
|
||||||
|
button.setAttribute('data-value', value);
|
||||||
|
buttonImg.setAttribute('data-value', value);
|
||||||
|
button.appendChild(buttonImg);
|
||||||
|
contentDiv.appendChild(button);
|
||||||
|
}
|
||||||
|
contentDiv.style.width = this.width_ + 'px';
|
||||||
|
dropdownDiv.appendChild(contentDiv);
|
||||||
|
|
||||||
|
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
|
||||||
|
|
||||||
|
// Calculate positioning based on the field position.
|
||||||
|
var scale = this.sourceBlock_.workspace.scale;
|
||||||
|
var bBox = { width: this.size_.width, height: this.size_.height };
|
||||||
|
bBox.width *= scale;
|
||||||
|
bBox.height *= scale;
|
||||||
|
var position = this.fieldGroup_.getBoundingClientRect();
|
||||||
|
var primaryX = position.left + bBox.width / 2;
|
||||||
|
var primaryY = position.top + bBox.height;
|
||||||
|
var secondaryX = primaryX;
|
||||||
|
var secondaryY = position.top;
|
||||||
|
// Set bounds to workspace; show the drop-down.
|
||||||
|
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
|
||||||
|
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
|
||||||
|
this.onHide_.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for when a button is clicked inside the drop-down.
|
||||||
|
* Should be bound to the FieldIconMenu.
|
||||||
|
* @param {Event} e DOM event for the click/touch
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private buttonClick_ = function (e: any) {
|
||||||
|
let value = e.target.getAttribute('data-value');
|
||||||
|
this.setValue(value);
|
||||||
|
Blockly.DropDownDiv.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for when the drop-down is hidden.
|
||||||
|
*/
|
||||||
|
private onHide_ = function () {
|
||||||
|
Blockly.DropDownDiv.content_.removeAttribute('role');
|
||||||
|
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
|
||||||
|
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
|
||||||
|
};
|
||||||
|
}
|
@ -1,12 +1,14 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": false,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"declaration": true,
|
"module": "commonjs",
|
||||||
"out": "../built/editor.js",
|
"outDir": "../built/editor",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"newLine": "LF",
|
"newLine": "LF",
|
||||||
"sourceMap": false
|
"sourceMap": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"declaration": true
|
||||||
}
|
}
|
||||||
}
|
}
|
After Width: | Height: | Size: 375 KiB |
BIN
legoresources/MC22122017/01b - MakeCode - basicdesign@2x.png
Normal file
After Width: | Height: | Size: 384 KiB |
After Width: | Height: | Size: 383 KiB |
After Width: | Height: | Size: 418 KiB |
BIN
legoresources/MC22122017/02a - MakeCode - portselector@2x.png
Normal file
After Width: | Height: | Size: 386 KiB |
BIN
legoresources/MC22122017/03a - MakeCode - all elements@2x.png
Normal file
After Width: | Height: | Size: 442 KiB |
BIN
legoresources/MC22122017/03b - MakeCode - motorsync@2x.png
Normal file
After Width: | Height: | Size: 404 KiB |
BIN
legoresources/MC22122017/04a - MakeCode - medmotor@2x.png
Normal file
After Width: | Height: | Size: 430 KiB |
BIN
legoresources/MC22122017/04b - MakeCode - medmotor@2x.png
Normal file
After Width: | Height: | Size: 428 KiB |
BIN
legoresources/MC22122017/05a - MakeCode - large motor@2x.png
Normal file
After Width: | Height: | Size: 426 KiB |
BIN
legoresources/MC22122017/05b - MakeCode - large motor@2x.png
Normal file
After Width: | Height: | Size: 425 KiB |
BIN
legoresources/MC22122017/06 - MakeCode - color - 1@2x.png
Normal file
After Width: | Height: | Size: 428 KiB |
BIN
legoresources/MC22122017/06 - MakeCode - color - 2@2x.png
Normal file
After Width: | Height: | Size: 422 KiB |
BIN
legoresources/MC22122017/06 - MakeCode - color - 3@2x.png
Normal file
After Width: | Height: | Size: 429 KiB |
BIN
legoresources/MC22122017/07a - MakeCode - Gyro@2x.png
Normal file
After Width: | Height: | Size: 423 KiB |
BIN
legoresources/MC22122017/07b - MakeCode - Gyro@2x.png
Normal file
After Width: | Height: | Size: 413 KiB |
BIN
legoresources/MC22122017/08 - MakeCode - UltraSound@2x.png
Normal file
After Width: | Height: | Size: 408 KiB |
BIN
legoresources/MC22122017/09a - MakeCode - display image@2x.png
Normal file
After Width: | Height: | Size: 478 KiB |
BIN
legoresources/MC22122017/10a - MakeCode – mouseover@2x.png
Normal file
After Width: | Height: | Size: 407 KiB |
BIN
legoresources/MC22122017/10b - MakeCode – mouseover@2x.png
Normal file
After Width: | Height: | Size: 408 KiB |
BIN
legoresources/MC22122017/10c - MakeCode - popup w-overlay@2x.png
Normal file
After Width: | Height: | Size: 351 KiB |
BIN
legoresources/MC22122017/11a - MakeCode - delete block@2x.png
Normal file
After Width: | Height: | Size: 346 KiB |
BIN
legoresources/MC22122017/11b - MakeCode - delete block@2x.png
Normal file
After Width: | Height: | Size: 366 KiB |
BIN
legoresources/MC22122017/12a - MakeCode - fullscreen@2x.png
Normal file
After Width: | Height: | Size: 382 KiB |
BIN
legoresources/MC22122017/12b - MakeCode - fullscreen@2x.png
Normal file
After Width: | Height: | Size: 424 KiB |
BIN
legoresources/MC22122017/Loader - 1@2x.png
Normal file
After Width: | Height: | Size: 132 KiB |
BIN
legoresources/MC22122017/Loader – 2@2x.png
Normal file
After Width: | Height: | Size: 132 KiB |
BIN
legoresources/MC22122017/XX-blocks@2x.png
Normal file
After Width: | Height: | Size: 270 KiB |
5914
legoresources/MakeCode_overview.ai
Normal file
@ -123,11 +123,6 @@
|
|||||||
"String.substr": "Return a substring of the current string.",
|
"String.substr": "Return a substring of the current string.",
|
||||||
"String.substr|param|length": "number of characters to extract",
|
"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",
|
"String.substr|param|start": "first character index; can be negative from counting from the end, eg:0",
|
||||||
"console": "Reading and writing data to the console output.",
|
|
||||||
"console.log": "Write a line of text to the console output.",
|
|
||||||
"console.logValue": "Write a name:value pair as a line of text to the console output.",
|
|
||||||
"console.logValue|param|name": "name of the value stream, eg: \"x\"",
|
|
||||||
"console.logValue|param|value": "to write",
|
|
||||||
"control": "Program controls and events.",
|
"control": "Program controls and events.",
|
||||||
"control.AnimationQueue.cancel": "Cancels the current running animation and clears the queue",
|
"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.AnimationQueue.runUntilDone": "Runs 'render' in a loop until it returns false or the 'stop' function is called",
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
"String.length|block": "length of %VALUE",
|
"String.length|block": "length of %VALUE",
|
||||||
"String.substr|block": "substring of %this=text|from %start|of length %length",
|
"String.substr|block": "substring of %this=text|from %start|of length %length",
|
||||||
"String|block": "String",
|
"String|block": "String",
|
||||||
"console.logValue|block": "console|log value %name|= %value",
|
|
||||||
"console.log|block": "console|log %text",
|
|
||||||
"console|block": "console",
|
|
||||||
"control.assert|block": "assert %cond|with value %code",
|
"control.assert|block": "assert %cond|with value %code",
|
||||||
"control.deviceSerialNumber|block": "device serial number",
|
"control.deviceSerialNumber|block": "device serial number",
|
||||||
"control.millis|block": "millis (ms)",
|
"control.millis|block": "millis (ms)",
|
||||||
@ -46,7 +43,6 @@
|
|||||||
"{id:category}Arrays": "Arrays",
|
"{id:category}Arrays": "Arrays",
|
||||||
"{id:category}Boolean": "Boolean",
|
"{id:category}Boolean": "Boolean",
|
||||||
"{id:category}Buffer": "Buffer",
|
"{id:category}Buffer": "Buffer",
|
||||||
"{id:category}Console": "Console",
|
|
||||||
"{id:category}Control": "Control",
|
"{id:category}Control": "Control",
|
||||||
"{id:category}Helpers": "Helpers",
|
"{id:category}Helpers": "Helpers",
|
||||||
"{id:category}Loops": "Loops",
|
"{id:category}Loops": "Loops",
|
||||||
|
@ -17,8 +17,7 @@
|
|||||||
"control.cpp",
|
"control.cpp",
|
||||||
"control.ts",
|
"control.ts",
|
||||||
"serial.cpp",
|
"serial.cpp",
|
||||||
"serial.ts",
|
"serial.ts"
|
||||||
"console.ts"
|
|
||||||
],
|
],
|
||||||
"testFiles": [
|
"testFiles": [
|
||||||
"test.ts"
|
"test.ts"
|
||||||
|
@ -8,5 +8,8 @@
|
|||||||
"sensors.ColorSensor.onColorDetected|param|handler": "the code to run when detected",
|
"sensors.ColorSensor.onColorDetected|param|handler": "the code to run when detected",
|
||||||
"sensors.ColorSensor.onLightChanged": "Registers code to run when the ambient light changes.",
|
"sensors.ColorSensor.onLightChanged": "Registers code to run when the ambient light changes.",
|
||||||
"sensors.ColorSensor.onLightChanged|param|condition": "the light condition",
|
"sensors.ColorSensor.onLightChanged|param|condition": "the light condition",
|
||||||
"sensors.ColorSensor.onLightChanged|param|handler": "the code to run when detected"
|
"sensors.ColorSensor.onLightChanged|param|handler": "the code to run when detected",
|
||||||
|
"sensors.ColorSensor.pauseForColor": "Waits for the given color to be detected",
|
||||||
|
"sensors.ColorSensor.pauseForColor|param|color": "the color to detect",
|
||||||
|
"sensors.ColorSensor.pauseForLight": "Waits for the given color to be detected"
|
||||||
}
|
}
|
@ -13,14 +13,16 @@
|
|||||||
"LightCondition.Dark|block": "dark",
|
"LightCondition.Dark|block": "dark",
|
||||||
"LightIntensityMode.Ambient|block": "ambient light",
|
"LightIntensityMode.Ambient|block": "ambient light",
|
||||||
"LightIntensityMode.Reflected|block": "reflected light",
|
"LightIntensityMode.Reflected|block": "reflected light",
|
||||||
"sensors.ColorSensor.color|block": "`icons.colorSensor` %sensor| color",
|
"sensors.ColorSensor.color|block": "%sensor| color",
|
||||||
"sensors.ColorSensor.light|block": "`icons.colorSensor` %sensor|%mode",
|
"sensors.ColorSensor.light|block": "%sensor|%mode",
|
||||||
"sensors.ColorSensor.onColorDetected|block": "on `icons.colorSensor` %sensor|detected color %color",
|
"sensors.ColorSensor.onColorDetected|block": "on %sensor|detected color %color",
|
||||||
"sensors.ColorSensor.onLightChanged|block": "on `icons.colorSensor` %sensor|%mode|%condition",
|
"sensors.ColorSensor.onLightChanged|block": "on %sensor|%mode|%condition",
|
||||||
"sensors.color1|block": "1",
|
"sensors.ColorSensor.pauseForColor|block": "pause %sensor|for color %color",
|
||||||
"sensors.color2|block": "2",
|
"sensors.ColorSensor.pauseForLight|block": "pause %sensor|for %mode|light %condition",
|
||||||
"sensors.color3|block": "3",
|
"sensors.color1|block": "color 1",
|
||||||
"sensors.color4|block": "4",
|
"sensors.color2|block": "color 2",
|
||||||
|
"sensors.color3|block": "color 3",
|
||||||
|
"sensors.color4|block": "color 4",
|
||||||
"sensors|block": "sensors",
|
"sensors|block": "sensors",
|
||||||
"{id:category}Sensors": "Sensors",
|
"{id:category}Sensors": "Sensors",
|
||||||
"{id:group}Color Sensor": "Color Sensor"
|
"{id:group}Color Sensor": "Color Sensor"
|
||||||
|
@ -56,6 +56,7 @@ namespace sensors {
|
|||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(port)
|
super(port)
|
||||||
|
this._setMode(ColorSensorMode.None);
|
||||||
this.thresholdDetector = new sensors.internal.ThresholdDetector(this.id());
|
this.thresholdDetector = new sensors.internal.ThresholdDetector(this.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,13 +69,20 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setMode(m: ColorSensorMode) {
|
setMode(m: ColorSensorMode) {
|
||||||
|
if (m == ColorSensorMode.AmbientLightIntensity) {
|
||||||
|
this.thresholdDetector.setLowThreshold(5);
|
||||||
|
this.thresholdDetector.setHighThreshold(20);
|
||||||
|
} else {
|
||||||
|
this.thresholdDetector.setLowThreshold(20);
|
||||||
|
this.thresholdDetector.setHighThreshold(80);
|
||||||
|
}
|
||||||
this._setMode(m)
|
this._setMode(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current color mode
|
* Gets the current color mode
|
||||||
*/
|
*/
|
||||||
colorMode() {
|
colorMode() {
|
||||||
return <ColorSensorMode>this.mode;
|
return <ColorSensorMode>this.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,12 +107,11 @@ namespace sensors {
|
|||||||
* @param handler the code to run when detected
|
* @param handler the code to run when detected
|
||||||
*/
|
*/
|
||||||
//% help=sensors/color-sensor/on-color-detected
|
//% help=sensors/color-sensor/on-color-detected
|
||||||
//% block="on `icons.colorSensor` %sensor|detected color %color"
|
//% block="on %sensor|detected color %color"
|
||||||
//% blockId=colorOnColorDetected
|
//% blockId=colorOnColorDetected
|
||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=100 blockGap=8
|
//% weight=100 blockGap=8
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
||||||
@ -115,17 +122,36 @@ namespace sensors {
|
|||||||
control.raiseEvent(this._id, v);
|
control.raiseEvent(this._id, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the given color to be detected
|
||||||
|
* @param color the color to detect
|
||||||
|
*/
|
||||||
|
//% help=sensors/color-sensor/pause-for-color
|
||||||
|
//% block="pause %sensor|for color %color"
|
||||||
|
//% blockId=colorPauseForColorDetected
|
||||||
|
//% parts="colorsensor"
|
||||||
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
|
//% weight=99 blockGap=8
|
||||||
|
//% group="Color Sensor"
|
||||||
|
pauseForColor(color: ColorSensorColor) {
|
||||||
|
this.setMode(ColorSensorMode.Color);
|
||||||
|
if (this.color() != color) {
|
||||||
|
const v = this._colorEventValue(<number>color);
|
||||||
|
control.waitForEvent(this._id, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current color from the color sensor.
|
* Get the current color from the color sensor.
|
||||||
* @param sensor the color sensor to query the request
|
* @param sensor the color sensor to query the request
|
||||||
*/
|
*/
|
||||||
//% help=sensors/color-sensor/color
|
//% help=sensors/color-sensor/color
|
||||||
//% block="`icons.colorSensor` %sensor| color"
|
//% block="%sensor| color"
|
||||||
//% blockId=colorGetColor
|
//% blockId=colorGetColor
|
||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=99
|
//% weight=99
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
color(): ColorSensorColor {
|
color(): ColorSensorColor {
|
||||||
@ -139,17 +165,34 @@ namespace sensors {
|
|||||||
* @param handler the code to run when detected
|
* @param handler the code to run when detected
|
||||||
*/
|
*/
|
||||||
//% help=sensors/color-sensor/on-light-changed
|
//% help=sensors/color-sensor/on-light-changed
|
||||||
//% block="on `icons.colorSensor` %sensor|%mode|%condition"
|
//% block="on %sensor|%mode|%condition"
|
||||||
//% blockId=colorOnLightChanged
|
//% blockId=colorOnLightChanged
|
||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=89 blockGap=8
|
//% weight=89 blockGap=8
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
onLightChanged(mode: LightIntensityMode, condition: LightCondition, handler: () => void) {
|
onLightChanged(mode: LightIntensityMode, condition: LightCondition, handler: () => void) {
|
||||||
control.onEvent(this._id, <number>condition, handler);
|
|
||||||
this.setMode(<ColorSensorMode><number>mode)
|
this.setMode(<ColorSensorMode><number>mode)
|
||||||
|
control.onEvent(this._id, <number>condition, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the given color to be detected
|
||||||
|
* @param color the color to detect
|
||||||
|
*/
|
||||||
|
//% help=sensors/color-sensor/pause-for-light
|
||||||
|
//% block="pause %sensor|for %mode|light %condition"
|
||||||
|
//% blockId=colorPauseForLight
|
||||||
|
//% parts="colorsensor"
|
||||||
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
|
//% weight=88 blockGap=8
|
||||||
|
//% group="Color Sensor"
|
||||||
|
pauseForLight(mode: LightIntensityMode, condition: LightCondition) {
|
||||||
|
this.setMode(<ColorSensorMode><number>mode)
|
||||||
|
if (this.thresholdDetector.state != <number>condition)
|
||||||
|
control.waitForEvent(this._id, <number>condition)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,13 +200,12 @@ namespace sensors {
|
|||||||
* @param sensor the color sensor port
|
* @param sensor the color sensor port
|
||||||
*/
|
*/
|
||||||
//% help=sensors/color-sensor/light
|
//% help=sensors/color-sensor/light
|
||||||
//% block="`icons.colorSensor` %sensor|%mode"
|
//% block="%sensor|%mode"
|
||||||
//% blockId=colorLight
|
//% blockId=colorLight
|
||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=88
|
//% sensor.fieldEditor="ports"
|
||||||
|
//% weight=87
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
light(mode: LightIntensityMode) {
|
light(mode: LightIntensityMode) {
|
||||||
this.setMode(<ColorSensorMode><number>mode)
|
this.setMode(<ColorSensorMode><number>mode)
|
||||||
@ -181,15 +223,15 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% whenUsed block="1" weight=95 fixedInstance jres=icons.port1
|
//% whenUsed block="color 1" weight=95 fixedInstance jres=icons.port1
|
||||||
export const color1: ColorSensor = new ColorSensor(1)
|
export const color1: ColorSensor = new ColorSensor(1)
|
||||||
|
|
||||||
//% whenUsed block="2" weight=90 fixedInstance jres=icons.port2
|
//% whenUsed block="color 2" weight=90 fixedInstance jres=icons.port2
|
||||||
export const color2: ColorSensor = new ColorSensor(2)
|
export const color2: ColorSensor = new ColorSensor(2)
|
||||||
|
|
||||||
//% whenUsed block="3" weight=90 fixedInstance jres=icons.port3
|
//% whenUsed block="color 3" weight=90 fixedInstance jres=icons.port3
|
||||||
export const color3: ColorSensor = new ColorSensor(3)
|
export const color3: ColorSensor = new ColorSensor(3)
|
||||||
|
|
||||||
//% whenUsed block="4" weight=90 fixedInstance jres=icons.port4
|
//% whenUsed block="color 4" weight=90 fixedInstance jres=icons.port4
|
||||||
export const color4: ColorSensor = new ColorSensor(4)
|
export const color4: ColorSensor = new ColorSensor(4)
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,6 @@
|
|||||||
"brick.Button.pauseUntil": "Waits until the event is raised",
|
"brick.Button.pauseUntil": "Waits until the event is raised",
|
||||||
"brick.Button.pauseUntil|param|ev": "the event to wait for",
|
"brick.Button.pauseUntil|param|ev": "the event to wait for",
|
||||||
"brick.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
"brick.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
||||||
"brick._imagePicker": "An image",
|
|
||||||
"brick._imagePicker|param|image": "the image",
|
|
||||||
"brick.buttonDown": "Down button on the EV3 Brick.",
|
"brick.buttonDown": "Down button on the EV3 Brick.",
|
||||||
"brick.buttonEnter": "Enter button on the EV3 Brick.",
|
"brick.buttonEnter": "Enter button on the EV3 Brick.",
|
||||||
"brick.buttonLeft": "Left button on the EV3 Brick.",
|
"brick.buttonLeft": "Left button on the EV3 Brick.",
|
||||||
@ -31,18 +29,21 @@
|
|||||||
"brick.clearScreen": "Clears the screen",
|
"brick.clearScreen": "Clears the screen",
|
||||||
"brick.lightPattern": "Pattern block.",
|
"brick.lightPattern": "Pattern block.",
|
||||||
"brick.lightPattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
"brick.lightPattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||||
"brick.print": "Show text on the screen.",
|
"brick.printLine": "Show text on the screen at a specific line.",
|
||||||
"brick.print|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
"brick.printLine|param|line": "the line number to print the text at, eg: 0",
|
||||||
"brick.print|param|x": "the starting position's x coordinate, eg: 0",
|
"brick.printLine|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||||
"brick.print|param|y": "the starting position's x coordinate, eg: 0",
|
"brick.printPorts": "Prints the port states on the screen",
|
||||||
"brick.setPixel": "Sets a pixel on or off",
|
"brick.setLight": "Set lights.",
|
||||||
"brick.setPixel|param|on": "a value indicating if the pixel should be on or off",
|
"brick.setLight|param|pattern": "the lights pattern to use.",
|
||||||
"brick.setPixel|param|x": "the starting position's x coordinate, eg: 0",
|
|
||||||
"brick.setPixel|param|y": "the starting position's x coordinate, eg: 0",
|
|
||||||
"brick.setStatusLight": "Set lights.",
|
|
||||||
"brick.setStatusLight|param|pattern": "the lights pattern to use.",
|
|
||||||
"brick.showImage": "Shows an image on screen",
|
"brick.showImage": "Shows an image on screen",
|
||||||
"brick.showImage|param|image": "image to draw",
|
"brick.showImage|param|image": "image to draw",
|
||||||
|
"console": "Reading and writing data to the console output.\n\nReading and writing data to the console output.",
|
||||||
|
"console.addListener": "Adds a listener for the log messages",
|
||||||
|
"console.log": "Write a line of text to the console output.",
|
||||||
|
"console.logValue": "Write a name:value pair as a line of text to the console output.",
|
||||||
|
"console.logValue|param|name": "name of the value stream, eg: \"x\"",
|
||||||
|
"console.logValue|param|value": "to write",
|
||||||
|
"console.sendToScreen": "Sends the log messages to the brick screen and uses the brick up and down buttons to scroll.",
|
||||||
"control": "Program controls and events.",
|
"control": "Program controls and events.",
|
||||||
"control.allocateNotifyEvent": "Allocates the next user notification event",
|
"control.allocateNotifyEvent": "Allocates the next user notification event",
|
||||||
"control.deviceFirmwareVersion": "Determine the version of system software currently running.",
|
"control.deviceFirmwareVersion": "Determine the version of system software currently running.",
|
||||||
@ -51,33 +52,51 @@
|
|||||||
"control.raiseEvent": "Announce that an event happened to registered handlers.",
|
"control.raiseEvent": "Announce that an event happened to registered handlers.",
|
||||||
"control.raiseEvent|param|src": "ID of the Component that generated the event",
|
"control.raiseEvent|param|src": "ID of the Component that generated the event",
|
||||||
"control.raiseEvent|param|value": "Component specific code indicating the cause of the event.",
|
"control.raiseEvent|param|value": "Component specific code indicating the cause of the event.",
|
||||||
"motors.Motor.isReady": "Returns a value indicating if the motor is still running a previous command.",
|
"motors.Motor.angle": "Gets motor angle.",
|
||||||
"motors.Motor.move": "Moves the motor by a number of rotations, degress or seconds",
|
"motors.Motor.clearCounts": "Clears the motor count",
|
||||||
"motors.Motor.move|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
"motors.Motor.speed": "Gets motor actual speed.",
|
||||||
"motors.Motor.move|param|unit": "the meaning of the value",
|
"motors.Motor.tacho": "Gets motor tachometer count.",
|
||||||
"motors.Motor.move|param|value": "the move quantity, eg: 2",
|
"motors.Motor.toString": "Returns the status of the motor",
|
||||||
"motors.Motor.pauseUntilReady": "Pauses the execution until the previous command finished.",
|
"motors.MotorBase.isReady": "Returns a value indicating if the motor is still running a previous command.",
|
||||||
"motors.Motor.pauseUntilReady|param|timeOut": "optional maximum pausing time in milliseconds",
|
"motors.MotorBase.move": "Moves the motor by a number of rotations, degress or seconds",
|
||||||
"motors.Motor.reset": "Resets the motor(s).",
|
"motors.MotorBase.move|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||||
"motors.Motor.setBrake": "Sets the automatic brake on or off when the motor is off",
|
"motors.MotorBase.move|param|unit": "the meaning of the value",
|
||||||
"motors.Motor.setBrake|param|brake": "a value indicating if the motor should break when off",
|
"motors.MotorBase.move|param|value": "the move quantity, eg: 2",
|
||||||
"motors.Motor.setReversed": "Reverses the motor polarity",
|
"motors.MotorBase.pauseUntilReady": "Pauses the execution until the previous command finished.",
|
||||||
"motors.Motor.setSpeed": "Sets the speed of the motor.",
|
"motors.MotorBase.pauseUntilReady|param|timeOut": "optional maximum pausing time in milliseconds",
|
||||||
"motors.Motor.setSpeed|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
"motors.MotorBase.reset": "Resets the motor(s).",
|
||||||
"motors.Motor.stop": "Stops the motor(s).",
|
"motors.MotorBase.setBrake": "Sets the automatic brake on or off when the motor is off",
|
||||||
"motors.SingleMotor.angle": "Gets motor ration angle.",
|
"motors.MotorBase.setBrake|param|brake": "a value indicating if the motor should break when off",
|
||||||
"motors.SingleMotor.clearCount": "Clears the motor count",
|
"motors.MotorBase.setReversed": "Reverses the motor polarity",
|
||||||
"motors.SingleMotor.speed": "Gets motor actual speed.",
|
"motors.MotorBase.setSpeed": "Sets the speed of the motor.",
|
||||||
|
"motors.MotorBase.setSpeed|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||||
|
"motors.MotorBase.stop": "Stops the motor(s).",
|
||||||
|
"motors.SynchedMotorPair.drive": "Makes a differential drive robot move with a given speed (%) and rotation rate (deg/s)\nusing a unicycle model.",
|
||||||
|
"motors.SynchedMotorPair.drive|param|rotationSpeed": "rotation of the robot around the center point, eg: 30",
|
||||||
|
"motors.SynchedMotorPair.drive|param|speed": "speed of the center point between motors, eg: 10",
|
||||||
|
"motors.SynchedMotorPair.drive|param|value": "the amount of movement, eg: 2",
|
||||||
|
"motors.SynchedMotorPair.setDimensions": "Sets the wheels radius and base length of a directional drive robot",
|
||||||
|
"motors.SynchedMotorPair.setDimensions|param|wheelRadius": "@param baseLength ",
|
||||||
"motors.SynchedMotorPair.steer": "Turns the motor and the follower motor by a number of rotations",
|
"motors.SynchedMotorPair.steer": "Turns the motor and the follower motor by a number of rotations",
|
||||||
"motors.SynchedMotorPair.steer|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
"motors.SynchedMotorPair.steer|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||||
"motors.SynchedMotorPair.steer|param|steering": "the ratio of power sent to the follower motor, from ``-100`` to ``100``",
|
"motors.SynchedMotorPair.steer|param|turnRatio": "the ratio of power sent to the follower motor, from ``-200`` to ``200``, eg: 0",
|
||||||
"motors.SynchedMotorPair.steer|param|unit": "the meaning of the value",
|
"motors.SynchedMotorPair.steer|param|unit": "the meaning of the value",
|
||||||
"motors.SynchedMotorPair.steer|param|value": "the move quantity, eg: 2",
|
"motors.SynchedMotorPair.steer|param|value": "the move quantity, eg: 2",
|
||||||
"motors.SynchedMotorPair.tank": "The Move Tank block can make a robot drive forward, backward, turn, or stop. \nUse the Move Tank block for robot vehicles that have two Large Motors, \nwith one motor driving the left side of the vehicle and the other the right side. \nYou can make the two motors go at different speeds or in different directions \nto make your robot turn.",
|
"motors.SynchedMotorPair.tank": "The Move Tank block can make a robot drive forward, backward, turn, or stop. \nUse the Move Tank block for robot vehicles that have two Large Motors, \nwith one motor driving the left side of the vehicle and the other the right side. \nYou can make the two motors go at different speeds or in different directions \nto make your robot turn.",
|
||||||
"motors.SynchedMotorPair.tank|param|speedRight": "the speed on the right motor, eg: 50",
|
"motors.SynchedMotorPair.tank|param|speedRight": "the speed on the right motor, eg: 50",
|
||||||
"motors.SynchedMotorPair.tank|param|unit": "@param speedLeft the speed on the left motor, eg: 50",
|
"motors.SynchedMotorPair.tank|param|unit": "@param speedLeft the speed on the left motor, eg: 50",
|
||||||
"motors.SynchedMotorPair.tank|param|value": "the amount of movement, eg: 2",
|
"motors.SynchedMotorPair.tank|param|value": "the amount of movement, eg: 2",
|
||||||
|
"motors.SynchedMotorPair.toString": "Returns the name(s) of the motor",
|
||||||
|
"motors.mkCmd": "Allocates a message buffer",
|
||||||
|
"motors.mkCmd|param|addSize": "required additional bytes",
|
||||||
|
"motors.mkCmd|param|cmd": "command id",
|
||||||
|
"motors.mkCmd|param|out": "ports",
|
||||||
|
"motors.readPWM": "Sends and receives a message from the motors device",
|
||||||
|
"motors.readPWM|param|buf": "message buffer",
|
||||||
|
"motors.resetAllMotors": "Resets all motors",
|
||||||
"motors.stopAllMotors": "Stops all motors",
|
"motors.stopAllMotors": "Stops all motors",
|
||||||
|
"motors.writePWM": "Sends a command to the motors device",
|
||||||
|
"motors.writePWM|param|buf": "the command buffer",
|
||||||
"output.createBuffer": "Create a new zero-initialized buffer.",
|
"output.createBuffer": "Create a new zero-initialized buffer.",
|
||||||
"output.createBuffer|param|size": "number of bytes in the buffer",
|
"output.createBuffer|param|size": "number of bytes in the buffer",
|
||||||
"screen.clear": "Clear screen and reset font to normal.",
|
"screen.clear": "Clear screen and reset font to normal.",
|
||||||
|
@ -24,34 +24,40 @@
|
|||||||
"Output.CD|block": "C+D",
|
"Output.CD|block": "C+D",
|
||||||
"Output.C|block": "C",
|
"Output.C|block": "C",
|
||||||
"Output.D|block": "D",
|
"Output.D|block": "D",
|
||||||
"brick.Button.isPressed|block": "`icons.brickButtons` %button|is pressed",
|
"brick.Button.isPressed|block": "%button|is pressed",
|
||||||
"brick.Button.onEvent|block": "on `icons.brickButtons` %button|%event",
|
"brick.Button.onEvent|block": "on %button|%event",
|
||||||
"brick.Button.pauseUntil|block": "pause until `icons.brickButtons` %button|%event",
|
"brick.Button.pauseUntil|block": "pause until %button|%event",
|
||||||
"brick.Button.wasPressed|block": "`icons.brickButtons` %button|was pressed",
|
"brick.Button.wasPressed|block": "%button|was pressed",
|
||||||
"brick._imagePicker|block": "%image",
|
|
||||||
"brick.buttonDown|block": "down",
|
"brick.buttonDown|block": "down",
|
||||||
"brick.buttonEnter|block": "enter",
|
"brick.buttonEnter|block": "enter",
|
||||||
"brick.buttonLeft|block": "left",
|
"brick.buttonLeft|block": "left",
|
||||||
"brick.buttonRight|block": "right",
|
"brick.buttonRight|block": "right",
|
||||||
"brick.buttonUp|block": "up",
|
"brick.buttonUp|block": "up",
|
||||||
"brick.clearScreen|block": "`icons.brickDisplay` clear screen",
|
"brick.clearScreen|block": "clear screen",
|
||||||
"brick.lightPattern|block": "%pattern",
|
"brick.lightPattern|block": "%pattern",
|
||||||
"brick.print|block": "`icons.brickDisplay` print %text| at x: %x| y: %y",
|
"brick.printLine|block": "print %text| at line %line",
|
||||||
"brick.setPixel|block": "`icons.brickDisplay` set pixel %on| at x: %x| y: %y",
|
"brick.printPorts|block": "print ports",
|
||||||
"brick.setStatusLight|block": "set `icons.brickButtons` to %pattern=led_pattern",
|
"brick.setLight|block": "set light to %pattern=led_pattern",
|
||||||
"brick.showImage|block": "`icons.brickDisplay` show image %image=screen_image_picker",
|
"brick.showImage|block": "show image %image=screen_image_picker",
|
||||||
"brick|block": "brick",
|
"brick|block": "brick",
|
||||||
|
"console.logValue|block": "console|log value %name|= %value",
|
||||||
|
"console.log|block": "console|log %text",
|
||||||
|
"console.sendToScreen|block": "send console to screen",
|
||||||
|
"console|block": "console",
|
||||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||||
"control|block": "control",
|
"control|block": "control",
|
||||||
"motors.Motor.move|block": "move `icons.motorLarge` %motor|for %value|%unit|at %speed|%",
|
"motors.Motor.angle|block": "%motor|angle",
|
||||||
"motors.Motor.pauseUntilReady|block": "%motor|pause until ready",
|
"motors.Motor.clearCounts|block": "%motor|clear counts",
|
||||||
"motors.Motor.setBrake|block": "set `icons.motorLarge` %motor|brake %brake",
|
"motors.Motor.speed|block": "%motor|speed",
|
||||||
"motors.Motor.setReversed|block": "set `icons.motorLarge` %motor|reversed %reversed",
|
"motors.Motor.tacho|block": "%motor|tacho",
|
||||||
"motors.Motor.setSpeed|block": "set speed of `icons.motorLarge` %motor|to %speed|%",
|
"motors.MotorBase.move|block": "move %motor|for %value|%unit|at %speed|%",
|
||||||
"motors.SingleMotor.angle|block": "`icons.motorLarge` %motor|angle",
|
"motors.MotorBase.pauseUntilReady|block": "%motor|pause until ready",
|
||||||
"motors.SingleMotor.speed|block": "`icons.motorLarge` %motor|speed",
|
"motors.MotorBase.setBrake|block": "set %motor|brake %brake",
|
||||||
"motors.SynchedMotorPair.steer|block": "steer %chassis|%steering|%|at speed %speed|%|by %value|%unit",
|
"motors.MotorBase.setReversed|block": "set %motor|reversed %reversed",
|
||||||
"motors.SynchedMotorPair.tank|block": "tank %chassis|left %speedLeft|%|right %speedRight|%|by %value|%unit",
|
"motors.MotorBase.setSpeed|block": "set speed of %motor|to %speed|%",
|
||||||
|
"motors.SynchedMotorPair.drive|block": "drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s|for %value|%unit",
|
||||||
|
"motors.SynchedMotorPair.steer|block": "steer %chassis turn by|%turnRatio|at speed %speed|%|for %value|%unit",
|
||||||
|
"motors.SynchedMotorPair.tank|block": "tank %chassis|left %speedLeft|%|right %speedRight|%|for %value|%unit",
|
||||||
"motors.largeAB|block": "large A+B",
|
"motors.largeAB|block": "large A+B",
|
||||||
"motors.largeAD|block": "large A+D",
|
"motors.largeAD|block": "large A+D",
|
||||||
"motors.largeA|block": "large A",
|
"motors.largeA|block": "large A",
|
||||||
@ -71,6 +77,7 @@
|
|||||||
"sensors|block": "sensors",
|
"sensors|block": "sensors",
|
||||||
"serial|block": "serial",
|
"serial|block": "serial",
|
||||||
"{id:category}Brick": "Brick",
|
"{id:category}Brick": "Brick",
|
||||||
|
"{id:category}Console": "Console",
|
||||||
"{id:category}Control": "Control",
|
"{id:category}Control": "Control",
|
||||||
"{id:category}Image": "Image",
|
"{id:category}Image": "Image",
|
||||||
"{id:category}Images": "Images",
|
"{id:category}Images": "Images",
|
||||||
|
@ -66,6 +66,7 @@ namespace brick {
|
|||||||
|
|
||||||
//% hidden
|
//% hidden
|
||||||
_update(curr: boolean) {
|
_update(curr: boolean) {
|
||||||
|
if (this == null) return
|
||||||
if (this._isPressed == curr) return
|
if (this._isPressed == curr) return
|
||||||
this._isPressed = curr
|
this._isPressed = curr
|
||||||
if (curr) {
|
if (curr) {
|
||||||
@ -85,7 +86,7 @@ namespace brick {
|
|||||||
* @param button the button to query the request
|
* @param button the button to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/button/is-pressed
|
//% help=input/button/is-pressed
|
||||||
//% block="`icons.brickButtons` %button|is pressed"
|
//% block="%button|is pressed"
|
||||||
//% blockId=buttonIsPressed
|
//% blockId=buttonIsPressed
|
||||||
//% parts="brick"
|
//% parts="brick"
|
||||||
//% blockNamespace=brick
|
//% blockNamespace=brick
|
||||||
@ -100,11 +101,11 @@ namespace brick {
|
|||||||
* @param button the button to query the request
|
* @param button the button to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/button/was-pressed
|
//% help=input/button/was-pressed
|
||||||
//% block="`icons.brickButtons` %button|was pressed"
|
//% block="%button|was pressed"
|
||||||
//% blockId=buttonWasPressed
|
//% blockId=buttonWasPressed
|
||||||
//% parts="brick"
|
//% parts="brick"
|
||||||
//% blockNamespace=brick
|
//% blockNamespace=brick
|
||||||
//% weight=80 blockGap=8
|
//% weight=80
|
||||||
//% group="Buttons"
|
//% group="Buttons"
|
||||||
wasPressed() {
|
wasPressed() {
|
||||||
const r = this._wasPressed
|
const r = this._wasPressed
|
||||||
@ -119,7 +120,7 @@ namespace brick {
|
|||||||
* @param body code to run when the event is raised
|
* @param body code to run when the event is raised
|
||||||
*/
|
*/
|
||||||
//% help=input/button/on-event
|
//% help=input/button/on-event
|
||||||
//% blockId=buttonEvent block="on `icons.brickButtons` %button|%event"
|
//% blockId=buttonEvent block="on %button|%event"
|
||||||
//% parts="brick"
|
//% parts="brick"
|
||||||
//% blockNamespace=brick
|
//% blockNamespace=brick
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
@ -133,7 +134,7 @@ namespace brick {
|
|||||||
* @param ev the event to wait for
|
* @param ev the event to wait for
|
||||||
*/
|
*/
|
||||||
//% help=input/button/pause-until
|
//% help=input/button/pause-until
|
||||||
//% blockId=buttonWaitUntil block="pause until `icons.brickButtons` %button|%event"
|
//% blockId=buttonWaitUntil block="pause until %button|%event"
|
||||||
//% parts="brick"
|
//% parts="brick"
|
||||||
//% blockNamespace=brick
|
//% blockNamespace=brick
|
||||||
//% weight=98 blockGap=8
|
//% weight=98 blockGap=8
|
||||||
@ -248,9 +249,9 @@ namespace brick {
|
|||||||
* Set lights.
|
* Set lights.
|
||||||
* @param pattern the lights pattern to use.
|
* @param pattern the lights pattern to use.
|
||||||
*/
|
*/
|
||||||
//% blockId=setLights block="set `icons.brickButtons` to %pattern=led_pattern"
|
//% blockId=setLights block="set light to %pattern=led_pattern"
|
||||||
//% weight=100 group="Light"
|
//% weight=100 group="Buttons"
|
||||||
export function setStatusLight(pattern: number): void {
|
export function setLight(pattern: number): void {
|
||||||
if (currPattern === pattern)
|
if (currPattern === pattern)
|
||||||
return
|
return
|
||||||
currPattern = pattern
|
currPattern = pattern
|
||||||
|
106
libs/core/console.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/// <reference no-default-lib="true"/>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reading and writing data to the console output.
|
||||||
|
*/
|
||||||
|
//% weight=12 color=#002050 icon="\uf120"
|
||||||
|
//% advanced=true
|
||||||
|
namespace console {
|
||||||
|
type Listener = (text: string) => void;
|
||||||
|
|
||||||
|
const listeners: Listener[] = [
|
||||||
|
(text: string) => serial.writeLine(text)
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a line of text to the console output.
|
||||||
|
* @param value to send
|
||||||
|
*/
|
||||||
|
//% weight=90
|
||||||
|
//% help=console/log blockGap=8
|
||||||
|
//% blockId=console_log block="console|log %text"
|
||||||
|
export function log(text: string): void {
|
||||||
|
for (let i = 0; i < listeners.length; ++i)
|
||||||
|
listeners[i](text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a name:value pair as a line of text to the console output.
|
||||||
|
* @param name name of the value stream, eg: "x"
|
||||||
|
* @param value to write
|
||||||
|
*/
|
||||||
|
//% weight=88 blockGap=8
|
||||||
|
//% help=console/log-value
|
||||||
|
//% blockId=console_log_value block="console|log value %name|= %value"
|
||||||
|
export function logValue(name: string, value: number): void {
|
||||||
|
log(`${name}: ${value}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener for the log messages
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
//%
|
||||||
|
export function addListener(listener: (text: string) => void) {
|
||||||
|
if (!listener) return;
|
||||||
|
listeners.push(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the log messages to the brick screen and uses the brick up and down buttons to scroll.
|
||||||
|
*/
|
||||||
|
//% blockId=logsendtostreen block="send console to screen"
|
||||||
|
//% weight=1
|
||||||
|
export function sendToScreen(): void {
|
||||||
|
console.screen.attach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace console.screen {
|
||||||
|
const maxLines = 100;
|
||||||
|
const screenLines = 8;
|
||||||
|
let lines: string[];
|
||||||
|
let scrollPosition = 0;
|
||||||
|
|
||||||
|
export function attach() {
|
||||||
|
if (!lines) {
|
||||||
|
lines = [];
|
||||||
|
console.addListener(log);
|
||||||
|
brick.buttonUp.onEvent(ButtonEvent.Click, () => scroll(-1))
|
||||||
|
brick.buttonDown.onEvent(ButtonEvent.Click, () => scroll(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function printLog() {
|
||||||
|
brick.clearScreen()
|
||||||
|
if (!lines) return;
|
||||||
|
for (let i = 0; i < screenLines; ++i) {
|
||||||
|
const line = lines[i + scrollPosition];
|
||||||
|
if (line)
|
||||||
|
brick.print(line, 0, 4 + i * brick.LINE_HEIGHT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scroll(pos: number) {
|
||||||
|
if (!pos) return;
|
||||||
|
|
||||||
|
scrollPosition += pos >> 0;
|
||||||
|
if (scrollPosition >= lines.length) scrollPosition = lines.length - 1;
|
||||||
|
if (scrollPosition < 0) scrollPosition = 0;
|
||||||
|
printLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(msg: string): void {
|
||||||
|
lines.push(msg);
|
||||||
|
if (lines.length + 5 > maxLines) {
|
||||||
|
lines.splice(0, maxLines - lines.length);
|
||||||
|
scrollPosition = Math.min(scrollPosition, lines.length - 1)
|
||||||
|
}
|
||||||
|
// move down scroll once it gets large than the screen
|
||||||
|
if (lines.length > screenLines
|
||||||
|
&& lines.length >= scrollPosition + screenLines) {
|
||||||
|
scrollPosition++;
|
||||||
|
}
|
||||||
|
printLog();
|
||||||
|
}
|
||||||
|
}
|
@ -1,260 +1,260 @@
|
|||||||
namespace images {
|
namespace images {
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsBigSmile = screen.unpackPNG(hex``);
|
export const expressionsBigSmile = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsHeartLarge = screen.unpackPNG(hex``);
|
export const expressionsHeartLarge = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsHeartSmall = screen.unpackPNG(hex``);
|
export const expressionsHeartSmall = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsMouth1open = screen.unpackPNG(hex``);
|
export const expressionsMouth1open = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsMouth1shut = screen.unpackPNG(hex``);
|
export const expressionsMouth1shut = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsMouth2open = screen.unpackPNG(hex``);
|
export const expressionsMouth2open = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsMouth2shut = screen.unpackPNG(hex``);
|
export const expressionsMouth2shut = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsSad = screen.unpackPNG(hex``);
|
export const expressionsSad = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsSick = screen.unpackPNG(hex``);
|
export const expressionsSick = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsSmile = screen.unpackPNG(hex``);
|
export const expressionsSmile = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsSwearing = screen.unpackPNG(hex``);
|
export const expressionsSwearing = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsTalking = screen.unpackPNG(hex``);
|
export const expressionsTalking = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsWink = screen.unpackPNG(hex``);
|
export const expressionsWink = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const expressionsZzz = screen.unpackPNG(hex``);
|
export const expressionsZzz = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesAngry = screen.unpackPNG(hex``);
|
export const eyesAngry = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesAwake = screen.unpackPNG(hex``);
|
export const eyesAwake = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesBlackEye = screen.unpackPNG(hex``);
|
export const eyesBlackEye = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesBottomLeft = screen.unpackPNG(hex``);
|
export const eyesBottomLeft = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesBottomRight = screen.unpackPNG(hex``);
|
export const eyesBottomRight = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesCrazy1 = screen.unpackPNG(hex``);
|
export const eyesCrazy1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesCrazy2 = screen.unpackPNG(hex``);
|
export const eyesCrazy2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesDisappointed = screen.unpackPNG(hex``);
|
export const eyesDisappointed = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesDizzy = screen.unpackPNG(hex``);
|
export const eyesDizzy = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesDown = screen.unpackPNG(hex``);
|
export const eyesDown = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesEvil = screen.unpackPNG(hex``);
|
export const eyesEvil = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesHurt = screen.unpackPNG(hex``);
|
export const eyesHurt = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesKnockedOut = screen.unpackPNG(hex``);
|
export const eyesKnockedOut = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesLove = screen.unpackPNG(hex``);
|
export const eyesLove = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesMiddleLeft = screen.unpackPNG(hex``);
|
export const eyesMiddleLeft = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesMiddleRight = screen.unpackPNG(hex``);
|
export const eyesMiddleRight = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesNeutral = screen.unpackPNG(hex``);
|
export const eyesNeutral = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesNuclear = screen.unpackPNG(hex``);
|
export const eyesNuclear = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesPinchLeft = screen.unpackPNG(hex``);
|
export const eyesPinchLeft = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesPinchMiddle = screen.unpackPNG(hex``);
|
export const eyesPinchMiddle = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesPinchRight = screen.unpackPNG(hex``);
|
export const eyesPinchRight = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesSleeping = screen.unpackPNG(hex``);
|
export const eyesSleeping = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesTear = screen.unpackPNG(hex``);
|
export const eyesTear = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesTiredLeft = screen.unpackPNG(hex``);
|
export const eyesTiredLeft = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesTiredMiddle = screen.unpackPNG(hex``);
|
export const eyesTiredMiddle = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesTiredRight = screen.unpackPNG(hex``);
|
export const eyesTiredRight = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesToxic = screen.unpackPNG(hex``);
|
export const eyesToxic = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesUp = screen.unpackPNG(hex``);
|
export const eyesUp = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const eyesWinking = screen.unpackPNG(hex``);
|
export const eyesWinking = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationAccept = screen.unpackPNG(hex``);
|
export const informationAccept = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationBackward = screen.unpackPNG(hex``);
|
export const informationBackward = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationDecline = screen.unpackPNG(hex``);
|
export const informationDecline = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationForward = screen.unpackPNG(hex``);
|
export const informationForward = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationLeft = screen.unpackPNG(hex``);
|
export const informationLeft = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationNoGo = screen.unpackPNG(hex``);
|
export const informationNoGo = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationQuestionMark = screen.unpackPNG(hex``);
|
export const informationQuestionMark = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationRight = screen.unpackPNG(hex``);
|
export const informationRight = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationStop1 = screen.unpackPNG(hex``);
|
export const informationStop1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationStop2 = screen.unpackPNG(hex``);
|
export const informationStop2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationThumbsDown = screen.unpackPNG(hex``);
|
export const informationThumbsDown = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationThumbsUp = screen.unpackPNG(hex``);
|
export const informationThumbsUp = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const informationWarning = screen.unpackPNG(hex``);
|
export const informationWarning = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoColorSensor = screen.unpackPNG(hex``);
|
export const legoColorSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoEv3icon = screen.unpackPNG(hex``);
|
export const legoEv3icon = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoEv3 = screen.unpackPNG(hex``);
|
export const legoEv3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoGyroSensor = screen.unpackPNG(hex``);
|
export const legoGyroSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoIrBeacon = screen.unpackPNG(hex``);
|
export const legoIrBeacon = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoIrSensor = screen.unpackPNG(hex``);
|
export const legoIrSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoLego = screen.unpackPNG(hex``);
|
export const legoLego = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoLargeMotor = screen.unpackPNG(hex``);
|
export const legoLargeMotor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoMindstorms = screen.unpackPNG(hex``);
|
export const legoMindstorms = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoMediumMotor = screen.unpackPNG(hex``);
|
export const legoMediumMotor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoSoundSensor = screen.unpackPNG(hex``);
|
export const legoSoundSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoTempSensor = screen.unpackPNG(hex``);
|
export const legoTempSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoTouchSensor = screen.unpackPNG(hex``);
|
export const legoTouchSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const legoUsSensor = screen.unpackPNG(hex``);
|
export const legoUsSensor = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsBomb = screen.unpackPNG(hex``);
|
export const objectsBomb = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsBoom = screen.unpackPNG(hex``);
|
export const objectsBoom = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsFire = screen.unpackPNG(hex``);
|
export const objectsFire = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsFlowers = screen.unpackPNG(hex``);
|
export const objectsFlowers = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsForest = screen.unpackPNG(hex``);
|
export const objectsForest = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsLightOff = screen.unpackPNG(hex``);
|
export const objectsLightOff = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsLightOn = screen.unpackPNG(hex``);
|
export const objectsLightOn = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsLightning = screen.unpackPNG(hex``);
|
export const objectsLightning = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsNight = screen.unpackPNG(hex``);
|
export const objectsNight = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsPirate = screen.unpackPNG(hex``);
|
export const objectsPirate = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsSnow = screen.unpackPNG(hex``);
|
export const objectsSnow = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const objectsTarget = screen.unpackPNG(hex``);
|
export const objectsTarget = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressBar0 = screen.unpackPNG(hex``);
|
export const progressBar0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressBar1 = screen.unpackPNG(hex``);
|
export const progressBar1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressBar2 = screen.unpackPNG(hex``);
|
export const progressBar2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressBar3 = screen.unpackPNG(hex``);
|
export const progressBar3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressBar4 = screen.unpackPNG(hex``);
|
export const progressBar4 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDial0 = screen.unpackPNG(hex``);
|
export const progressDial0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDial1 = screen.unpackPNG(hex``);
|
export const progressDial1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDial2 = screen.unpackPNG(hex``);
|
export const progressDial2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDial3 = screen.unpackPNG(hex``);
|
export const progressDial3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDial4 = screen.unpackPNG(hex``);
|
export const progressDial4 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDots0 = screen.unpackPNG(hex``);
|
export const progressDots0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDots1 = screen.unpackPNG(hex``);
|
export const progressDots1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDots2 = screen.unpackPNG(hex``);
|
export const progressDots2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressDots3 = screen.unpackPNG(hex``);
|
export const progressDots3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressHourglass0 = screen.unpackPNG(hex``);
|
export const progressHourglass0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressHourglass1 = screen.unpackPNG(hex``);
|
export const progressHourglass1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressHourglass2 = screen.unpackPNG(hex``);
|
export const progressHourglass2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressTimer0 = screen.unpackPNG(hex``);
|
export const progressTimer0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressTimer1 = screen.unpackPNG(hex``);
|
export const progressTimer1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressTimer2 = screen.unpackPNG(hex``);
|
export const progressTimer2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressTimer3 = screen.unpackPNG(hex``);
|
export const progressTimer3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressTimer4 = screen.unpackPNG(hex``);
|
export const progressTimer4 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressWaterLevel0 = screen.unpackPNG(hex``);
|
export const progressWaterLevel0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressWaterLevel1 = screen.unpackPNG(hex``);
|
export const progressWaterLevel1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressWaterLevel2 = screen.unpackPNG(hex``);
|
export const progressWaterLevel2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const progressWaterLevel3 = screen.unpackPNG(hex``);
|
export const progressWaterLevel3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemAccept1 = screen.unpackPNG(hex``);
|
export const systemAccept1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemAccept2 = screen.unpackPNG(hex``);
|
export const systemAccept2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemAlert = screen.unpackPNG(hex``);
|
export const systemAlert = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemBox = screen.unpackPNG(hex``);
|
export const systemBox = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemBusy0 = screen.unpackPNG(hex``);
|
export const systemBusy0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemBusy1 = screen.unpackPNG(hex``);
|
export const systemBusy1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemDecline1 = screen.unpackPNG(hex``);
|
export const systemDecline1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemDecline2 = screen.unpackPNG(hex``);
|
export const systemDecline2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemDotEmpty = screen.unpackPNG(hex``);
|
export const systemDotEmpty = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemDotFull = screen.unpackPNG(hex``);
|
export const systemDotFull = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemEv3small = screen.unpackPNG(hex``);
|
export const systemEv3small = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemPlay = screen.unpackPNG(hex``);
|
export const systemPlay = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider0 = screen.unpackPNG(hex``);
|
export const systemSlider0 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider1 = screen.unpackPNG(hex``);
|
export const systemSlider1 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider2 = screen.unpackPNG(hex``);
|
export const systemSlider2 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider3 = screen.unpackPNG(hex``);
|
export const systemSlider3 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider4 = screen.unpackPNG(hex``);
|
export const systemSlider4 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider5 = screen.unpackPNG(hex``);
|
export const systemSlider5 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider6 = screen.unpackPNG(hex``);
|
export const systemSlider6 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider7 = screen.unpackPNG(hex``);
|
export const systemSlider7 = screen.unpackPNG(hex``);
|
||||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||||
export const systemSlider8 = screen.unpackPNG(hex``);
|
export const systemSlider8 = screen.unpackPNG(hex``);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,11 @@ namespace sensors.internal {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getActiveSensors(): Sensor[] {
|
||||||
|
init();
|
||||||
|
return sensorInfos.filter(si => si.sensor && si.sensor.isActive()).map(si => si.sensor);
|
||||||
|
}
|
||||||
|
|
||||||
function readUartInfo(port: number, mode: number) {
|
function readUartInfo(port: number, mode: number) {
|
||||||
let buf = output.createBuffer(UartCtlOff.Size)
|
let buf = output.createBuffer(UartCtlOff.Size)
|
||||||
buf[UartCtlOff.Port] = port
|
buf[UartCtlOff.Port] = port
|
||||||
@ -196,7 +201,7 @@ namespace sensors.internal {
|
|||||||
private lowThreshold: number;
|
private lowThreshold: number;
|
||||||
private highThreshold: number;
|
private highThreshold: number;
|
||||||
private level: number;
|
private level: number;
|
||||||
private state: ThresholdState;
|
public state: ThresholdState;
|
||||||
|
|
||||||
constructor(id: number, min = 0, max = 100, lowThreshold = 20, highThreshold = 80) {
|
constructor(id: number, min = 0, max = 100, lowThreshold = 20, highThreshold = 80) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -209,6 +214,7 @@ namespace sensors.internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setLevel(level: number) {
|
public setLevel(level: number) {
|
||||||
|
if (this == null) return
|
||||||
this.level = this.clampValue(level);
|
this.level = this.clampValue(level);
|
||||||
|
|
||||||
if (this.level >= this.highThreshold) {
|
if (this.level >= this.highThreshold) {
|
||||||
|
@ -14,7 +14,7 @@ enum Output {
|
|||||||
//% block="C+D"
|
//% block="C+D"
|
||||||
CD = Output.C | Output.D,
|
CD = Output.C | Output.D,
|
||||||
//% block="A+D"
|
//% block="A+D"
|
||||||
AD = Output.B | Output.C,
|
AD = Output.A | Output.D,
|
||||||
//% block="All"
|
//% block="All"
|
||||||
ALL = 0x0f
|
ALL = 0x0f
|
||||||
}
|
}
|
||||||
@ -53,48 +53,81 @@ namespace motors {
|
|||||||
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
||||||
if (!motorMM) control.fail("no motor file")
|
if (!motorMM) control.fail("no motor file")
|
||||||
|
|
||||||
resetMotors()
|
resetAllMotors()
|
||||||
|
|
||||||
let buf = output.createBuffer(1)
|
const buf = output.createBuffer(1)
|
||||||
buf[0] = DAL.opProgramStart
|
buf[0] = DAL.opProgramStart
|
||||||
writePWM(buf)
|
writePWM(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
function writePWM(buf: Buffer): void {
|
/**
|
||||||
|
* Sends a command to the motors device
|
||||||
|
* @param buf the command buffer
|
||||||
|
*/
|
||||||
|
//%
|
||||||
|
export function writePWM(buf: Buffer): void {
|
||||||
init()
|
init()
|
||||||
pwmMM.write(buf)
|
pwmMM.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
function readPWM(buf: Buffer): number {
|
/**
|
||||||
|
* Sends and receives a message from the motors device
|
||||||
|
* @param buf message buffer
|
||||||
|
*/
|
||||||
|
//%
|
||||||
|
export function readPWM(buf: Buffer): void {
|
||||||
init()
|
init()
|
||||||
return pwmMM.read(buf);
|
pwmMM.read(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mkCmd(out: Output, cmd: number, addSize: number) {
|
/**
|
||||||
|
* Allocates a message buffer
|
||||||
|
* @param out ports
|
||||||
|
* @param cmd command id
|
||||||
|
* @param addSize required additional bytes
|
||||||
|
*/
|
||||||
|
//%
|
||||||
|
export function mkCmd(out: Output, cmd: number, addSize: number) {
|
||||||
const b = output.createBuffer(2 + addSize)
|
const b = output.createBuffer(2 + addSize)
|
||||||
b.setNumber(NumberFormat.UInt8LE, 0, cmd)
|
b.setNumber(NumberFormat.UInt8LE, 0, cmd)
|
||||||
b.setNumber(NumberFormat.UInt8LE, 1, out)
|
b.setNumber(NumberFormat.UInt8LE, 1, out)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetMotors() {
|
function outputToName(out: Output): string {
|
||||||
reset(Output.ALL)
|
let r = "";
|
||||||
|
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||||
|
if (out & (1 << i)) {
|
||||||
|
if (r.length > 0) r += "+";
|
||||||
|
r += "ABCD"[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops all motors
|
* Stops all motors
|
||||||
*/
|
*/
|
||||||
//% blockId=motorStopAll block="stop all motors"
|
//% blockId=motorStopAll block="stop all motors"
|
||||||
//% weight=97
|
//% weight=5
|
||||||
//% group="Motion"
|
//% group="Motion"
|
||||||
export function stopAllMotors() {
|
export function stopAllMotors() {
|
||||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||||
writePWM(b)
|
writePWM(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all motors
|
||||||
|
*/
|
||||||
|
//% group="Motion"
|
||||||
|
export function resetAllMotors() {
|
||||||
|
reset(Output.ALL)
|
||||||
|
}
|
||||||
|
|
||||||
//% fixedInstances
|
//% fixedInstances
|
||||||
export class Motor extends control.Component {
|
export class MotorBase extends control.Component {
|
||||||
protected _port: Output;
|
protected _port: Output;
|
||||||
|
protected _portName: string;
|
||||||
protected _brake: boolean;
|
protected _brake: boolean;
|
||||||
private _initialized: boolean;
|
private _initialized: boolean;
|
||||||
private _init: () => void;
|
private _init: () => void;
|
||||||
@ -104,6 +137,7 @@ namespace motors {
|
|||||||
constructor(port: Output, init: () => void, setSpeed: (speed: number) => void, move: (steps: boolean, stepsOrTime: number, speed: number) => void) {
|
constructor(port: Output, init: () => void, setSpeed: (speed: number) => void, move: (steps: boolean, stepsOrTime: number, speed: number) => void) {
|
||||||
super();
|
super();
|
||||||
this._port = port;
|
this._port = port;
|
||||||
|
this._portName = outputToName(this._port);
|
||||||
this._brake = false;
|
this._brake = false;
|
||||||
this._initialized = false;
|
this._initialized = false;
|
||||||
this._init = init;
|
this._init = init;
|
||||||
@ -125,7 +159,7 @@ namespace motors {
|
|||||||
* Sets the automatic brake on or off when the motor is off
|
* Sets the automatic brake on or off when the motor is off
|
||||||
* @param brake a value indicating if the motor should break when off
|
* @param brake a value indicating if the motor should break when off
|
||||||
*/
|
*/
|
||||||
//% blockId=outputMotorSetBrakeMode block="set `icons.motorLarge` %motor|brake %brake"
|
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake"
|
||||||
//% brake.fieldEditor=toggleonoff
|
//% brake.fieldEditor=toggleonoff
|
||||||
//% weight=60 blockGap=8
|
//% weight=60 blockGap=8
|
||||||
//% group="Motion"
|
//% group="Motion"
|
||||||
@ -137,7 +171,7 @@ namespace motors {
|
|||||||
/**
|
/**
|
||||||
* Reverses the motor polarity
|
* Reverses the motor polarity
|
||||||
*/
|
*/
|
||||||
//% blockId=motorSetReversed block="set `icons.motorLarge` %motor|reversed %reversed"
|
//% blockId=motorSetReversed block="set %motor|reversed %reversed"
|
||||||
//% reversed.fieldEditor=toggleonoff
|
//% reversed.fieldEditor=toggleonoff
|
||||||
//% weight=59
|
//% weight=59
|
||||||
//% group="Motion"
|
//% group="Motion"
|
||||||
@ -170,7 +204,7 @@ namespace motors {
|
|||||||
* Sets the speed of the motor.
|
* Sets the speed of the motor.
|
||||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||||
*/
|
*/
|
||||||
//% blockId=motorSetSpeed block="set speed of `icons.motorLarge` %motor|to %speed|%"
|
//% blockId=motorSetSpeed block="set speed of %motor|to %speed|%"
|
||||||
//% on.fieldEditor=toggleonoff
|
//% on.fieldEditor=toggleonoff
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
//% speed.min=-100 speed.max=100
|
//% speed.min=-100 speed.max=100
|
||||||
@ -190,7 +224,7 @@ namespace motors {
|
|||||||
* @param unit the meaning of the value
|
* @param unit the meaning of the value
|
||||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||||
*/
|
*/
|
||||||
//% blockId=motorMove block="move `icons.motorLarge` %motor|for %value|%unit|at %speed|%"
|
//% blockId=motorMove block="move %motor|for %value|%unit|at %speed|%"
|
||||||
//% weight=98 blockGap=8
|
//% weight=98 blockGap=8
|
||||||
//% speed.min=-100 speed.max=100
|
//% speed.min=-100 speed.max=100
|
||||||
//% group="Motion"
|
//% group="Motion"
|
||||||
@ -224,12 +258,19 @@ namespace motors {
|
|||||||
/**
|
/**
|
||||||
* Returns a value indicating if the motor is still running a previous command.
|
* Returns a value indicating if the motor is still running a previous command.
|
||||||
*/
|
*/
|
||||||
//%
|
//% group="Sensors"
|
||||||
isReady(): boolean {
|
isReady(): boolean {
|
||||||
this.init();
|
this.init();
|
||||||
const r = readPWM(mkCmd(this._port, DAL.opOutputTest, 0))
|
const buf = mkCmd(this._port, DAL.opOutputTest, 2);
|
||||||
// 0 = ready, 1 = busy
|
readPWM(buf)
|
||||||
return r == 0;
|
const flags = buf.getNumber(NumberFormat.UInt8LE, 2);
|
||||||
|
// TODO: FIX with ~ support
|
||||||
|
for(let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||||
|
const flag = 1 << i;
|
||||||
|
if ((this._port & flag) && (flags & flag))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -237,6 +278,7 @@ namespace motors {
|
|||||||
* @param timeOut optional maximum pausing time in milliseconds
|
* @param timeOut optional maximum pausing time in milliseconds
|
||||||
*/
|
*/
|
||||||
//% blockId=motorPauseUntilRead block="%motor|pause until ready"
|
//% blockId=motorPauseUntilRead block="%motor|pause until ready"
|
||||||
|
//% weight=97
|
||||||
//% group="Motion"
|
//% group="Motion"
|
||||||
pauseUntilReady(timeOut?: number) {
|
pauseUntilReady(timeOut?: number) {
|
||||||
pauseUntil(() => this.isReady(), timeOut);
|
pauseUntil(() => this.isReady(), timeOut);
|
||||||
@ -244,7 +286,7 @@ namespace motors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstances
|
//% fixedInstances
|
||||||
export class SingleMotor extends Motor {
|
export class Motor extends MotorBase {
|
||||||
private _large: boolean;
|
private _large: boolean;
|
||||||
|
|
||||||
constructor(port: Output, large: boolean) {
|
constructor(port: Output, large: boolean) {
|
||||||
@ -288,8 +330,9 @@ namespace motors {
|
|||||||
* Gets motor actual speed.
|
* Gets motor actual speed.
|
||||||
* @param motor the port which connects to the motor
|
* @param motor the port which connects to the motor
|
||||||
*/
|
*/
|
||||||
//% blockId=motorSpeed block="`icons.motorLarge` %motor|speed"
|
//% blockId=motorSpeed block="%motor|speed"
|
||||||
//% weight=72 blockGap=8
|
//% weight=72
|
||||||
|
//% blockGap=8
|
||||||
//% group="Sensors"
|
//% group="Sensors"
|
||||||
speed(): number {
|
speed(): number {
|
||||||
this.init();
|
this.init();
|
||||||
@ -297,10 +340,10 @@ namespace motors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets motor ration angle.
|
* Gets motor angle.
|
||||||
* @param motor the port which connects to the motor
|
* @param motor the port which connects to the motor
|
||||||
*/
|
*/
|
||||||
//% blockId=motorTachoCount block="`icons.motorLarge` %motor|angle"
|
//% blockId=motorTachoCount block="%motor|angle"
|
||||||
//% weight=70
|
//% weight=70
|
||||||
//% group="Sensors"
|
//% group="Sensors"
|
||||||
angle(): number {
|
angle(): number {
|
||||||
@ -308,11 +351,28 @@ namespace motors {
|
|||||||
return getMotorData(this._port).count;
|
return getMotorData(this._port).count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets motor tachometer count.
|
||||||
|
* @param motor the port which connects to the motor
|
||||||
|
*/
|
||||||
|
//% blockId=motorTachoCount block="%motor|tacho"
|
||||||
|
//% weight=69
|
||||||
|
//% blockGap=8
|
||||||
|
//% group="Sensors"
|
||||||
|
tacho(): number {
|
||||||
|
this.init();
|
||||||
|
return getMotorData(this._port).tachoCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the motor count
|
* Clears the motor count
|
||||||
*/
|
*/
|
||||||
//% group="Motion"
|
//% blockId=motorClearCount block="%motor|clear counts"
|
||||||
clearCount() {
|
//% weight=68
|
||||||
|
//% blockGap=8
|
||||||
|
//% group="Sensors"
|
||||||
|
clearCounts() {
|
||||||
this.init();
|
this.init();
|
||||||
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
|
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
|
||||||
writePWM(b)
|
writePWM(b)
|
||||||
@ -322,37 +382,49 @@ namespace motors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the motor
|
||||||
|
*/
|
||||||
|
//%
|
||||||
|
toString(): string {
|
||||||
|
return `${this._large ? "" : "M"}${this._portName} ${this.speed()}% ${this.angle()}>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="large A"
|
//% whenUsed fixedInstance block="large A"
|
||||||
export const largeA = new SingleMotor(Output.A, true);
|
export const largeA = new Motor(Output.A, true);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="large B"
|
//% whenUsed fixedInstance block="large B"
|
||||||
export const largeB = new SingleMotor(Output.B, true);
|
export const largeB = new Motor(Output.B, true);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="large C"
|
//% whenUsed fixedInstance block="large C"
|
||||||
export const largeC = new SingleMotor(Output.C, true);
|
export const largeC = new Motor(Output.C, true);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="large D"
|
//% whenUsed fixedInstance block="large D"
|
||||||
export const largeD = new SingleMotor(Output.D, true);
|
export const largeD = new Motor(Output.D, true);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="medium A"
|
//% whenUsed fixedInstance block="medium A"
|
||||||
export const mediumA = new SingleMotor(Output.A, false);
|
export const mediumA = new Motor(Output.A, false);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="medium B"
|
//% whenUsed fixedInstance block="medium B"
|
||||||
export const mediumB = new SingleMotor(Output.B, false);
|
export const mediumB = new Motor(Output.B, false);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="medium C"
|
//% whenUsed fixedInstance block="medium C"
|
||||||
export const mediumC = new SingleMotor(Output.C, false);
|
export const mediumC = new Motor(Output.C, false);
|
||||||
|
|
||||||
//% whenUsed fixedInstance block="medium D"
|
//% whenUsed fixedInstance block="medium D"
|
||||||
export const mediumD = new SingleMotor(Output.D, false);
|
export const mediumD = new Motor(Output.D, false);
|
||||||
|
|
||||||
//% fixedInstances
|
//% fixedInstances
|
||||||
export class SynchedMotorPair extends Motor {
|
export class SynchedMotorPair extends MotorBase {
|
||||||
|
private wheelRadius: number;
|
||||||
|
private baseLength: number;
|
||||||
|
|
||||||
constructor(ports: Output) {
|
constructor(ports: Output) {
|
||||||
super(ports, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
super(ports, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||||
|
this.wheelRadius = 3;
|
||||||
|
this.baseLength = 12;
|
||||||
this.markUsed();
|
this.markUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,18 +461,82 @@ namespace motors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns the motor and the follower motor by a number of rotations
|
* The Move Tank block can make a robot drive forward, backward, turn, or stop.
|
||||||
* @param value the move quantity, eg: 2
|
* Use the Move Tank block for robot vehicles that have two Large Motors,
|
||||||
* @param unit the meaning of the value
|
* with one motor driving the left side of the vehicle and the other the right side.
|
||||||
* @param steering the ratio of power sent to the follower motor, from ``-100`` to ``100``
|
* You can make the two motors go at different speeds or in different directions
|
||||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
* to make your robot turn.
|
||||||
|
* @param value the amount of movement, eg: 2
|
||||||
|
* @param unit
|
||||||
|
* @param speedLeft the speed on the left motor, eg: 50
|
||||||
|
* @param speedRight the speed on the right motor, eg: 50
|
||||||
*/
|
*/
|
||||||
//% blockId=motorPairTurn block="steer %chassis|%steering|%|at speed %speed|%|by %value|%unit"
|
//% blockId=motorPairTank block="tank %chassis|left %speedLeft|%|right %speedRight|%|for %value|%unit"
|
||||||
//% weight=9 blockGap=8
|
//% weight=9 blockGap=8
|
||||||
//% steering.min=-100 steering=100
|
//% speedLeft.min=-100 speedLeft=100
|
||||||
|
//% speedRight.min=-100 speedRight=100
|
||||||
//% inlineInputMode=inline
|
//% inlineInputMode=inline
|
||||||
//% group="Chassis"
|
//% group="Chassis"
|
||||||
steer(steering: number, speed: number, value: number, unit: MoveUnit) {
|
tank(speedLeft: number, speedRight: number, value: number, unit: MoveUnit) {
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
speedLeft = Math.clamp(-100, 100, speedLeft >> 0);
|
||||||
|
speedRight = Math.clamp(-100, 100, speedRight >> 0);
|
||||||
|
|
||||||
|
const speed = Math.abs(speedLeft) > Math.abs(speedRight) ? speedLeft : speedRight;
|
||||||
|
const turnRatio = speedLeft == speed
|
||||||
|
? (100 - speedRight / speedLeft * 100)
|
||||||
|
: (speedLeft / speedRight * 100 - 100);
|
||||||
|
this.steer(turnRatio, speed, value, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a differential drive robot move with a given speed (%) and rotation rate (deg/s)
|
||||||
|
* using a unicycle model.
|
||||||
|
* @param speed speed of the center point between motors, eg: 10
|
||||||
|
* @param rotationSpeed rotation of the robot around the center point, eg: 30
|
||||||
|
* @param value the amount of movement, eg: 2
|
||||||
|
* @param unit
|
||||||
|
*/
|
||||||
|
//% blockId=motorDrive block="drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s|for %value|%unit"
|
||||||
|
//% inlineInputMode=inline
|
||||||
|
//% group="Chassis"
|
||||||
|
//% weight=8 blockGap=8
|
||||||
|
drive(speed: number, rotationSpeed: number, value: number, unit: MoveUnit) {
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
// speed is expressed in %
|
||||||
|
const R = this.wheelRadius; // cm
|
||||||
|
const L = this.baseLength; // cm
|
||||||
|
const PI = 3.14;
|
||||||
|
const maxw = 170 / 60 * 2 * PI; // rad / s
|
||||||
|
const maxv = maxw * R; // cm / s
|
||||||
|
// speed is cm / s
|
||||||
|
const v = speed; // cm / s
|
||||||
|
const w = rotationSpeed / 360 * 2 * PI; // rad / s
|
||||||
|
|
||||||
|
const vr = (2 * v + w * L) / (2 * R); // rad / s
|
||||||
|
const vl = (2 * v - w * L) / (2 * R); // rad / s
|
||||||
|
|
||||||
|
const sr = vr / maxw * 100; // %
|
||||||
|
const sl = vl / maxw * 100; // %
|
||||||
|
|
||||||
|
this.tank(sr, sl, value, unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns the motor and the follower motor by a number of rotations
|
||||||
|
* @param turnRatio the ratio of power sent to the follower motor, from ``-200`` to ``200``, eg: 0
|
||||||
|
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||||
|
* @param value the move quantity, eg: 2
|
||||||
|
* @param unit the meaning of the value
|
||||||
|
*/
|
||||||
|
//% blockId=motorPairTurn block="steer %chassis turn by|%turnRatio|at speed %speed|%|for %value|%unit"
|
||||||
|
//% weight=6 blockGap=8
|
||||||
|
//% turnRatio.min=-200 turnRatio=200
|
||||||
|
//% inlineInputMode=inline
|
||||||
|
//% group="Chassis"
|
||||||
|
steer(turnRatio: number, speed: number, value: number, unit: MoveUnit) {
|
||||||
this.init();
|
this.init();
|
||||||
speed = Math.clamp(-100, 100, speed >> 0);
|
speed = Math.clamp(-100, 100, speed >> 0);
|
||||||
if (!speed) {
|
if (!speed) {
|
||||||
@ -408,7 +544,7 @@ namespace motors {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const turnRatio = Math.clamp(-200, 200, steering + 100 >> 0);
|
turnRatio = Math.clamp(-200, 200, turnRatio >> 0);
|
||||||
let useSteps: boolean;
|
let useSteps: boolean;
|
||||||
let stepsOrTime: number;
|
let stepsOrTime: number;
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
@ -421,7 +557,7 @@ namespace motors {
|
|||||||
useSteps = true;
|
useSteps = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stepsOrTime = value;
|
stepsOrTime = value >> 0;
|
||||||
useSteps = false;
|
useSteps = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -433,30 +569,33 @@ namespace motors {
|
|||||||
stepsOrTime: stepsOrTime,
|
stepsOrTime: stepsOrTime,
|
||||||
useBrake: this._brake
|
useBrake: this._brake
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the wheels radius and base length of a directional drive robot
|
||||||
|
* @param wheelRadius
|
||||||
|
* @param baseLength
|
||||||
|
*/
|
||||||
|
//% group="Chassis"
|
||||||
|
setDimensions(wheelRadius: number, baseLength: number): void {
|
||||||
|
this.wheelRadius = wheelRadius;
|
||||||
|
this.baseLength = baseLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Move Tank block can make a robot drive forward, backward, turn, or stop.
|
* Returns the name(s) of the motor
|
||||||
* Use the Move Tank block for robot vehicles that have two Large Motors,
|
|
||||||
* with one motor driving the left side of the vehicle and the other the right side.
|
|
||||||
* You can make the two motors go at different speeds or in different directions
|
|
||||||
* to make your robot turn.
|
|
||||||
* @param value the amount of movement, eg: 2
|
|
||||||
* @param unit
|
|
||||||
* @param speedLeft the speed on the left motor, eg: 50
|
|
||||||
* @param speedRight the speed on the right motor, eg: 50
|
|
||||||
*/
|
*/
|
||||||
//% blockId=motorPairTank block="tank %chassis|left %speedLeft|%|right %speedRight|%|by %value|%unit"
|
//%
|
||||||
//% weight=9 blockGap=8
|
toString(): string {
|
||||||
//% speedLeft.min=-100 speedLeft=100
|
this.init();
|
||||||
//% speedRight.min=-100 speedRight=100
|
|
||||||
//% inlineInputMode=inline
|
let r = outputToName(this._port);
|
||||||
//% group="Chassis"
|
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||||
tank(speedLeft: number, speedRight: number, value: number, unit: MoveUnit) {
|
if (this._port & (1 << i)) {
|
||||||
speedLeft = Math.clamp(speedLeft >> 0, -100, 100);
|
r += ` ${getMotorData(1 << i).actualSpeed}%`
|
||||||
speedRight = Math.clamp(speedRight >> 0, -100, 100);
|
}
|
||||||
const steering = (speedRight * 100 / speedLeft) >> 0;
|
}
|
||||||
this.steer(speedLeft, steering, value, unit);
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,8 +612,8 @@ namespace motors {
|
|||||||
export const largeCD = new SynchedMotorPair(Output.CD);
|
export const largeCD = new SynchedMotorPair(Output.CD);
|
||||||
|
|
||||||
function reset(out: Output) {
|
function reset(out: Output) {
|
||||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
writePWM(mkCmd(out, DAL.opOutputReset, 0))
|
||||||
writePWM(b)
|
writePWM(mkCmd(out, DAL.opOutputClearCount, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
function outOffset(out: Output) {
|
function outOffset(out: Output) {
|
||||||
@ -485,7 +624,7 @@ namespace motors {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MotorData {
|
export interface MotorData {
|
||||||
actualSpeed: number; // -100..+100
|
actualSpeed: number; // -100..+100
|
||||||
tachoCount: number;
|
tachoCount: number;
|
||||||
count: number;
|
count: number;
|
||||||
@ -494,7 +633,7 @@ namespace motors {
|
|||||||
// only a single output at a time
|
// only a single output at a time
|
||||||
function getMotorData(out: Output): MotorData {
|
function getMotorData(out: Output): MotorData {
|
||||||
init()
|
init()
|
||||||
let buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
const buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
||||||
return {
|
return {
|
||||||
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
||||||
tachoCount: buf.getNumber(NumberFormat.Int32LE, MotorDataOff.TachoCounts),
|
tachoCount: buf.getNumber(NumberFormat.Int32LE, MotorDataOff.TachoCounts),
|
||||||
@ -502,6 +641,11 @@ namespace motors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAllMotorData(): MotorData[] {
|
||||||
|
init();
|
||||||
|
return [Output.A, Output.B, Output.C, Output.D].map(out => getMotorData(out));
|
||||||
|
}
|
||||||
|
|
||||||
interface SyncOptions {
|
interface SyncOptions {
|
||||||
useSteps?: boolean;
|
useSteps?: boolean;
|
||||||
speed: number;
|
speed: number;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"linux.cpp",
|
"linux.cpp",
|
||||||
"mmap.cpp",
|
"mmap.cpp",
|
||||||
"control.cpp",
|
"control.cpp",
|
||||||
|
"console.ts",
|
||||||
"serialnumber.cpp",
|
"serialnumber.cpp",
|
||||||
"buttons.ts",
|
"buttons.ts",
|
||||||
"png.cpp",
|
"png.cpp",
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace brick {
|
namespace brick {
|
||||||
|
export const LINE_HEIGHT = 12;
|
||||||
|
|
||||||
//% shim=screen::_setPixel
|
//% shim=screen::_setPixel
|
||||||
function _setPixel(p0: uint32, p1: uint32, mode: Draw): void { }
|
function _setPixel(p0: uint32, p1: uint32, mode: Draw): void { }
|
||||||
|
|
||||||
@ -78,15 +80,6 @@ namespace brick {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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="`icons.brickDisplay` set pixel %on| at x: %x| y: %y"
|
|
||||||
//% weight=98 group="Screen"
|
|
||||||
//% x.min=0 x.max=178 y.min=0 y.max=128 on.fieldEditor=toggleonoff
|
|
||||||
export function setPixel(on: boolean, x: number, y: number) {
|
export function setPixel(on: boolean, x: number, y: number) {
|
||||||
x |= 0
|
x |= 0
|
||||||
y |= 0
|
y |= 0
|
||||||
@ -95,14 +88,20 @@ namespace brick {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show text on the screen.
|
* Show text on the screen at a specific line.
|
||||||
* @param text the text to print on the screen, eg: "Hello world"
|
* @param text the text to print on the screen, eg: "Hello world"
|
||||||
* @param x the starting position's x coordinate, eg: 0
|
* @param line the line number to print the text at, eg: 0
|
||||||
* @param y the starting position's x coordinate, eg: 0
|
|
||||||
*/
|
*/
|
||||||
//% blockId=screen_print block="`icons.brickDisplay` print %text| at x: %x| y: %y"
|
//% blockId=screen_print block="print %text| at line %line"
|
||||||
//% weight=99 group="Screen" inlineInputMode="inline" blockGap=8
|
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
|
||||||
//% x.min=0 x.max=178 y.min=0 y.max=128
|
//% line.min=0 line.max=9
|
||||||
|
export function printLine(text: string, line: number) {
|
||||||
|
const NUM_LINES = 9;
|
||||||
|
const offset = 5;
|
||||||
|
const y = offset + (Math.clamp(0, NUM_LINES, line) / (NUM_LINES + 2)) * DAL.LCD_HEIGHT;
|
||||||
|
brick.print(text, offset, y);
|
||||||
|
}
|
||||||
|
|
||||||
export function print(text: string, x: number, y: number, mode = Draw.Normal) {
|
export function print(text: string, x: number, y: number, mode = Draw.Normal) {
|
||||||
x |= 0
|
x |= 0
|
||||||
y |= 0
|
y |= 0
|
||||||
@ -137,8 +136,8 @@ namespace brick {
|
|||||||
* Shows an image on screen
|
* Shows an image on screen
|
||||||
* @param image image to draw
|
* @param image image to draw
|
||||||
*/
|
*/
|
||||||
//% blockId=screen_show_image block="`icons.brickDisplay` show image %image=screen_image_picker"
|
//% blockId=screen_show_image block="show image %image=screen_image_picker"
|
||||||
//% weight=95 group="Screen" blockGap=8
|
//% weight=100 group="Screen" blockGap=8
|
||||||
export function showImage(image: Image, delay: number = 400) {
|
export function showImage(image: Image, delay: number = 400) {
|
||||||
if (!image) return;
|
if (!image) return;
|
||||||
image.draw(0, 0, Draw.Normal);
|
image.draw(0, 0, Draw.Normal);
|
||||||
@ -152,19 +151,19 @@ namespace brick {
|
|||||||
* @param image the image
|
* @param image the image
|
||||||
*/
|
*/
|
||||||
//% blockId=screen_image_picker block="%image" shim=TD_ID
|
//% blockId=screen_image_picker block="%image" shim=TD_ID
|
||||||
//% image.fieldEditor="imagedropdown"
|
//% image.fieldEditor="images"
|
||||||
//% image.fieldOptions.columns=6
|
//% image.fieldOptions.columns=6
|
||||||
//% image.fieldOptions.hasSearchBar=true
|
//% image.fieldOptions.width=600
|
||||||
//% group="Screen" weight=0 blockHidden=1
|
//% group="Screen" weight=0 blockHidden=1
|
||||||
export function _imagePicker(image: Image): Image {
|
export function __imagePicker(image: Image): Image {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the screen
|
* Clears the screen
|
||||||
*/
|
*/
|
||||||
//% blockId=screen_clear_screen block="`icons.brickDisplay` clear screen"
|
//% blockId=screen_clear_screen block="clear screen"
|
||||||
//% weight=94 group="Screen" blockGap=8
|
//% weight=90 group="Screen"
|
||||||
export function clearScreen() {
|
export function clearScreen() {
|
||||||
screen.clear();
|
screen.clear();
|
||||||
}
|
}
|
||||||
@ -208,5 +207,36 @@ namespace brick {
|
|||||||
setLineCore(x, x1, y, mode);
|
setLineCore(x, x1, y, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the port states on the screen
|
||||||
|
*/
|
||||||
|
//% blockId=brickPrintPorts block="print ports"
|
||||||
|
//% weight=1 group="Screen"
|
||||||
|
export function printPorts() {
|
||||||
|
clearScreen();
|
||||||
|
|
||||||
|
// motors
|
||||||
|
const datas = motors.getAllMotorData();
|
||||||
|
for(let i = 0; i < datas.length; ++i) {
|
||||||
|
const data = datas[i];
|
||||||
|
if (!data.actualSpeed && !data.count) continue;
|
||||||
|
const x = i * 52;
|
||||||
|
print(`${data.actualSpeed}%`, x, brick.LINE_HEIGHT)
|
||||||
|
print(`${data.count}>`, x, 2 * brick.LINE_HEIGHT)
|
||||||
|
|
||||||
|
console.logValue(`speed.` + "ABCD"[i], data.actualSpeed);
|
||||||
|
console.logValue(`angle.` + "ABCD"[i], data.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sensors
|
||||||
|
const sis = sensors.internal.getActiveSensors();
|
||||||
|
for(let i =0; i < sis.length; ++i) {
|
||||||
|
const si = sis[i];
|
||||||
|
const x = (si.port() - 1) * 52;
|
||||||
|
const v = si._query();
|
||||||
|
print(`${v}`, x, 9 * brick.LINE_HEIGHT)
|
||||||
|
|
||||||
|
console.logValue(`sensor.` + si.port(), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ screen.clear()
|
|||||||
brick.print("PXT!", 10, 30, Draw.Quad)
|
brick.print("PXT!", 10, 30, Draw.Quad)
|
||||||
|
|
||||||
brick.drawRect(40, 40, 20, 10, Draw.Fill)
|
brick.drawRect(40, 40, 20, 10, Draw.Fill)
|
||||||
brick.setStatusLight(LightsPattern.Orange)
|
brick.setLight(LightsPattern.Orange)
|
||||||
|
|
||||||
brick.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
|
brick.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
|||||||
|
|
||||||
brick.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
brick.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
||||||
brick.drawRect(10, 70, 20, 10, Draw.Fill)
|
brick.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||||
brick.setStatusLight(LightsPattern.Red)
|
brick.setLight(LightsPattern.Red)
|
||||||
brick.setFont(brick.microbitFont())
|
brick.setFont(brick.microbitFont())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
|
|
||||||
//% color="#68C3E2" weight=100
|
//% color="#68C3E2" weight=100 icon="\uf106"
|
||||||
//% groups='["Light", "Buttons", "Screen"]'
|
//% groups='["Buttons", "Screen"]'
|
||||||
//% labelLineWidth=0
|
//% labelLineWidth=0
|
||||||
namespace brick {
|
namespace brick {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//% color="#C8509B" weight=95 icon="\uf192"
|
//% color="#C8509B" weight=95 icon="\uf10f"
|
||||||
//% labelLineWidth=0
|
//% labelLineWidth=0
|
||||||
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||||
//% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]'
|
//% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]'
|
||||||
namespace sensors {
|
namespace sensors {
|
||||||
}
|
}
|
||||||
|
|
||||||
//% color="#A5CA18" weight=90 icon="\uf185"
|
//% color="#A5CA18" weight=90 icon="\uf10d"
|
||||||
//% groups='["Motion", "Sensors", "Chassis"]'
|
//% groups='["Motion", "Sensors", "Chassis"]'
|
||||||
//% labelLineWidth=0
|
//% labelLineWidth=0
|
||||||
namespace motors {
|
namespace motors {
|
||||||
}
|
}
|
||||||
|
|
||||||
//% color="#D67923" weight=80
|
//% color="#D67923" weight=80 icon="\uf10e"
|
||||||
namespace music {
|
namespace music {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//% color="#48150C"
|
//% color="#5F3109" icon="\uf107"
|
||||||
namespace control {
|
namespace control {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"sensors.GyroSensor.angle|block": "`icons.gyroSensor` %sensor|angle",
|
"sensors.GyroSensor.angle|block": "%sensor|angle",
|
||||||
"sensors.GyroSensor.rate|block": "`icons.gyroSensor` %sensor|rotation rate",
|
"sensors.GyroSensor.rate|block": "%sensor|rotation rate",
|
||||||
"sensors.gyro1|block": "1",
|
"sensors.gyro1|block": "gyro 1",
|
||||||
"sensors.gyro2|block": "2",
|
"sensors.gyro2|block": "gyro 2",
|
||||||
"sensors.gyro3|block": "3",
|
"sensors.gyro3|block": "gyro 3",
|
||||||
"sensors.gyro4|block": "4",
|
"sensors.gyro4|block": "gyro 4",
|
||||||
"{id:category}Sensors": "Sensors",
|
"{id:category}Sensors": "Sensors",
|
||||||
"{id:group}Gyro Sensor": "Gyro Sensor"
|
"{id:group}Gyro Sensor": "Gyro Sensor"
|
||||||
}
|
}
|
@ -24,12 +24,11 @@ namespace sensors {
|
|||||||
* @param sensor the gyroscope to query the request
|
* @param sensor the gyroscope to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/gyro/angle
|
//% help=input/gyro/angle
|
||||||
//% block="`icons.gyroSensor` %sensor|angle"
|
//% block="%sensor|angle"
|
||||||
//% blockId=gyroGetAngle
|
//% blockId=gyroGetAngle
|
||||||
//% parts="gyroscope"
|
//% parts="gyroscope"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=65 blockGap=8
|
//% weight=65 blockGap=8
|
||||||
//% group="Gyro Sensor"
|
//% group="Gyro Sensor"
|
||||||
angle(): number {
|
angle(): number {
|
||||||
@ -42,12 +41,11 @@ namespace sensors {
|
|||||||
* @param sensor the gyroscope to query the request
|
* @param sensor the gyroscope to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/gyro/rate
|
//% help=input/gyro/rate
|
||||||
//% block="`icons.gyroSensor` %sensor|rotation rate"
|
//% block="%sensor|rotation rate"
|
||||||
//% blockId=gyroGetRate
|
//% blockId=gyroGetRate
|
||||||
//% parts="gyroscope"
|
//% parts="gyroscope"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=65 blockGap=8
|
//% weight=65 blockGap=8
|
||||||
//% group="Gyro Sensor"
|
//% group="Gyro Sensor"
|
||||||
rate(): number {
|
rate(): number {
|
||||||
@ -56,15 +54,15 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="1" jres=icons.port1
|
//% fixedInstance whenUsed block="gyro 1" jres=icons.port1
|
||||||
export const gyro1: GyroSensor = new GyroSensor(1)
|
export const gyro1: GyroSensor = new GyroSensor(1)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="2" weight=95 jres=icons.port2
|
//% fixedInstance whenUsed block="gyro 2" weight=95 jres=icons.port2
|
||||||
export const gyro2: GyroSensor = new GyroSensor(2)
|
export const gyro2: GyroSensor = new GyroSensor(2)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="3" jres=icons.port3
|
//% fixedInstance whenUsed block="gyro 3" jres=icons.port3
|
||||||
export const gyro3: GyroSensor = new GyroSensor(3)
|
export const gyro3: GyroSensor = new GyroSensor(3)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="4" jres=icons.port4
|
//% fixedInstance whenUsed block="gyro 4" jres=icons.port4
|
||||||
export const gyro4: GyroSensor = new GyroSensor(4)
|
export const gyro4: GyroSensor = new GyroSensor(4)
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"InfraredSensorEvent.ObjectDetected|block": "object detected",
|
"InfraredSensorEvent.ObjectDetected|block": "object detected",
|
||||||
"InfraredSensorEvent.ObjectNear|block": "object near",
|
"InfraredSensorEvent.ObjectNear|block": "object near",
|
||||||
"sensors.InfraredSensor.onEvent|block": "on `icons.infraredSensor` %sensor|%event",
|
"sensors.InfraredSensor.onEvent|block": "on %sensor|%event",
|
||||||
"sensors.InfraredSensor.pauseUntil|block": "pause until `icons.infraredSensor` %sensor| %event",
|
"sensors.InfraredSensor.pauseUntil|block": "pause until %sensor| %event",
|
||||||
"sensors.InfraredSensor.proximity|block": "`icons.infraredSensor` %sensor|proximity",
|
"sensors.InfraredSensor.proximity|block": "%sensor|proximity",
|
||||||
"sensors.InfraredSensor.remoteCommand|block": "`icons.infraredSensor` %sensor|remote command",
|
"sensors.InfraredSensor.remoteCommand|block": "%sensor|remote command",
|
||||||
"sensors.RemoteInfraredBeaconButton.isPressed|block": "`icons.infraredSensor` %button|is pressed",
|
"sensors.RemoteInfraredBeaconButton.isPressed|block": "%button|is pressed",
|
||||||
"sensors.RemoteInfraredBeaconButton.onEvent|block": "on `icons.infraredSensor` %button|%event",
|
"sensors.RemoteInfraredBeaconButton.onEvent|block": "on %button|%event",
|
||||||
"sensors.RemoteInfraredBeaconButton.wasPressed|block": "`icons.infraredSensor` %button|was pressed",
|
"sensors.RemoteInfraredBeaconButton.wasPressed|block": "%button|was pressed",
|
||||||
"sensors.infraredSensor1|block": "1",
|
"sensors.infraredSensor1|block": "infrared 1",
|
||||||
"sensors.infraredSensor2|block": "2",
|
"sensors.infraredSensor2|block": "infrared 2",
|
||||||
"sensors.infraredSensor3|block": "3",
|
"sensors.infraredSensor3|block": "infrared 3",
|
||||||
"sensors.infraredSensor4|block": "4",
|
"sensors.infraredSensor4|block": "infrared 4",
|
||||||
"sensors.remoteButtonBottomLeft|block": "bottom-left",
|
"sensors.remoteButtonBottomLeft|block": "bottom-left",
|
||||||
"sensors.remoteButtonBottomRight|block": "bottom-right",
|
"sensors.remoteButtonBottomRight|block": "bottom-right",
|
||||||
"sensors.remoteButtonCenter|block": "center",
|
"sensors.remoteButtonCenter|block": "center",
|
||||||
|
@ -93,7 +93,7 @@ namespace sensors {
|
|||||||
* @param button the remote button to query the request
|
* @param button the remote button to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/remote-infrared-beacon/is-pressed
|
//% help=input/remote-infrared-beacon/is-pressed
|
||||||
//% block="`icons.infraredSensor` %button|is pressed"
|
//% block="%button|is pressed"
|
||||||
//% blockId=remoteButtonIsPressed
|
//% blockId=remoteButtonIsPressed
|
||||||
//% parts="remote"
|
//% parts="remote"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
@ -108,11 +108,11 @@ namespace sensors {
|
|||||||
* @param button the remote button to query the request
|
* @param button the remote button to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/remote-infrared-beacon/was-pressed
|
//% help=input/remote-infrared-beacon/was-pressed
|
||||||
//% block="`icons.infraredSensor` %button|was pressed"
|
//% block="%button|was pressed"
|
||||||
//% blockId=remotebuttonWasPressed
|
//% blockId=remotebuttonWasPressed
|
||||||
//% parts="remote"
|
//% parts="remote"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=80 blockGap=8
|
//% weight=80
|
||||||
//% group="Remote Infrared Beacon"
|
//% group="Remote Infrared Beacon"
|
||||||
wasPressed() {
|
wasPressed() {
|
||||||
return this.button.wasPressed();
|
return this.button.wasPressed();
|
||||||
@ -125,7 +125,7 @@ namespace sensors {
|
|||||||
* @param body code to run when the event is raised
|
* @param body code to run when the event is raised
|
||||||
*/
|
*/
|
||||||
//% help=input/remote-infrared-beacon/on-event
|
//% help=input/remote-infrared-beacon/on-event
|
||||||
//% blockId=remotebuttonEvent block="on `icons.infraredSensor` %button|%event"
|
//% blockId=remotebuttonEvent block="on %button|%event"
|
||||||
//% parts="remote"
|
//% parts="remote"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
@ -189,11 +189,9 @@ namespace sensors {
|
|||||||
* @param handler the code to run when detected
|
* @param handler the code to run when detected
|
||||||
*/
|
*/
|
||||||
//% help=input/infrared/on
|
//% help=input/infrared/on
|
||||||
//% block="on `icons.infraredSensor` %sensor|%event"
|
//% block="on %sensor|%event"
|
||||||
//% blockId=infraredOn
|
//% blockId=infraredOn
|
||||||
//% parts="infraredsensor"
|
//% parts="infraredsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=100 blockGap=8
|
//% weight=100 blockGap=8
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
@ -205,11 +203,9 @@ namespace sensors {
|
|||||||
* Waits for the event to occur
|
* Waits for the event to occur
|
||||||
*/
|
*/
|
||||||
//% help=input/ultrasonic/wait
|
//% help=input/ultrasonic/wait
|
||||||
//% block="pause until `icons.infraredSensor` %sensor| %event"
|
//% block="pause until %sensor| %event"
|
||||||
//% blockId=infraredwait
|
//% blockId=infraredwait
|
||||||
//% parts="infraredsensor"
|
//% parts="infraredsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
@ -222,11 +218,9 @@ namespace sensors {
|
|||||||
* @param sensor the infrared sensor
|
* @param sensor the infrared sensor
|
||||||
*/
|
*/
|
||||||
//% help=input/infrared/proximity
|
//% help=input/infrared/proximity
|
||||||
//% block="`icons.infraredSensor` %sensor|proximity"
|
//% block="%sensor|proximity"
|
||||||
//% blockId=infraredGetProximity
|
//% blockId=infraredGetProximity
|
||||||
//% parts="infrared"
|
//% parts="infrared"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=65 blockGap=8
|
//% weight=65 blockGap=8
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
@ -240,13 +234,11 @@ namespace sensors {
|
|||||||
* @param sensor the infrared sensor
|
* @param sensor the infrared sensor
|
||||||
*/
|
*/
|
||||||
//% help=input/infrared/remote-command
|
//% help=input/infrared/remote-command
|
||||||
//% block="`icons.infraredSensor` %sensor|remote command"
|
//% block="%sensor|remote command"
|
||||||
//% blockId=infraredGetRemoteCommand
|
//% blockId=infraredGetRemoteCommand
|
||||||
//% parts="infrared"
|
//% parts="infrared"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=65 blockGap=8
|
//% weight=65
|
||||||
//% group="Infrared Sensor"
|
//% group="Infrared Sensor"
|
||||||
remoteCommand(): number {
|
remoteCommand(): number {
|
||||||
this._setMode(IrSensorMode.RemoteControl)
|
this._setMode(IrSensorMode.RemoteControl)
|
||||||
@ -260,16 +252,16 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="1" jres=icons.port1
|
//% fixedInstance whenUsed block="infrared 1" jres=icons.port1
|
||||||
export const infraredSensor1: InfraredSensor = new InfraredSensor(1)
|
export const infraredSensor1: InfraredSensor = new InfraredSensor(1)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="2" jres=icons.port2
|
//% fixedInstance whenUsed block="infrared 2" jres=icons.port2
|
||||||
export const infraredSensor2: InfraredSensor = new InfraredSensor(2)
|
export const infraredSensor2: InfraredSensor = new InfraredSensor(2)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="3" jres=icons.port3
|
//% fixedInstance whenUsed block="infrared 3" jres=icons.port3
|
||||||
export const infraredSensor3: InfraredSensor = new InfraredSensor(3)
|
export const infraredSensor3: InfraredSensor = new InfraredSensor(3)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="4" jres=icons.port4
|
//% fixedInstance whenUsed block="infrared 4" jres=icons.port4
|
||||||
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
"Sound.buffer": "Returns the underlaying Buffer object.",
|
"Sound.buffer": "Returns the underlaying Buffer object.",
|
||||||
"Sound.play": "Play sound.",
|
"Sound.play": "Play sound.",
|
||||||
"music": "Generation of music tones.",
|
"music": "Generation of music tones.",
|
||||||
"music._soundPicker": "A sound",
|
|
||||||
"music._soundPicker|param|sound": "the sound",
|
|
||||||
"music.beat": "Return the duration of a beat in milliseconds (the beat fraction).",
|
"music.beat": "Return the duration of a beat in milliseconds (the beat fraction).",
|
||||||
"music.beat|param|fraction": "the fraction of the current whole note, eg: BeatFraction.Half",
|
"music.beat|param|fraction": "the fraction of the current whole note, eg: BeatFraction.Half",
|
||||||
"music.changeTempoBy": "Change the tempo up or down by some amount of beats per minute (bpm).",
|
"music.changeTempoBy": "Change the tempo up or down by some amount of beats per minute (bpm).",
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
"Note.GSharp|block": "G#",
|
"Note.GSharp|block": "G#",
|
||||||
"SoundOutputDestination.Pin|block": "pin",
|
"SoundOutputDestination.Pin|block": "pin",
|
||||||
"SoundOutputDestination.Speaker|block": "speaker",
|
"SoundOutputDestination.Speaker|block": "speaker",
|
||||||
"music._soundPicker|block": "%sound",
|
|
||||||
"music.beat|block": "%fraction|beat",
|
"music.beat|block": "%fraction|beat",
|
||||||
"music.changeTempoBy|block": "change tempo by %value|(bpm)",
|
"music.changeTempoBy|block": "change tempo by %value|(bpm)",
|
||||||
"music.noteFrequency|block": "%note",
|
"music.noteFrequency|block": "%note",
|
||||||
|
@ -170,7 +170,7 @@ void playTone(int frequency, int ms) {
|
|||||||
//% blockId=music_stop_all_sounds block="stop all sounds"
|
//% blockId=music_stop_all_sounds block="stop all sounds"
|
||||||
//% parts="headphone"
|
//% parts="headphone"
|
||||||
//% blockNamespace=music
|
//% blockNamespace=music
|
||||||
//% weight=76 blockGap=8
|
//% weight=97
|
||||||
void stopAllSounds() {
|
void stopAllSounds() {
|
||||||
if (currentSample) {
|
if (currentSample) {
|
||||||
samplePtr = currentSample->length;
|
samplePtr = currentSample->length;
|
||||||
|
2
libs/music/shims.d.ts
vendored
@ -32,7 +32,7 @@ declare namespace music {
|
|||||||
//% blockId=music_stop_all_sounds block="stop all sounds"
|
//% blockId=music_stop_all_sounds block="stop all sounds"
|
||||||
//% parts="headphone"
|
//% parts="headphone"
|
||||||
//% blockNamespace=music
|
//% blockNamespace=music
|
||||||
//% weight=76 blockGap=8 shim=music::stopAllSounds
|
//% weight=97 shim=music::stopAllSounds
|
||||||
function stopAllSounds(): void;
|
function stopAllSounds(): void;
|
||||||
|
|
||||||
/** Makes a sound bound to a buffer in WAV format. */
|
/** Makes a sound bound to a buffer in WAV format. */
|
||||||
|
@ -264,7 +264,7 @@ namespace music {
|
|||||||
* @param sound the sound to play
|
* @param sound the sound to play
|
||||||
*/
|
*/
|
||||||
//% blockId=music_play_sound_effect_until_done block="play sound effect %sound|until done"
|
//% blockId=music_play_sound_effect_until_done block="play sound effect %sound|until done"
|
||||||
//% weight=98
|
//% weight=98 blockGap=8
|
||||||
export function playSoundEffectUntilDone(sound: Sound) {
|
export function playSoundEffectUntilDone(sound: Sound) {
|
||||||
if (!sound) return;
|
if (!sound) return;
|
||||||
sound.play();
|
sound.play();
|
||||||
@ -276,7 +276,7 @@ namespace music {
|
|||||||
*/
|
*/
|
||||||
//% blockId=music_sound_picker block="%sound" shim=TD_ID
|
//% blockId=music_sound_picker block="%sound" shim=TD_ID
|
||||||
//% weight=0 blockHidden=1
|
//% weight=0 blockHidden=1
|
||||||
export function _soundPicker(sound: Sound): Sound {
|
export function __soundPicker(sound: Sound): Sound {
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ namespace music {
|
|||||||
* @param sound the sound to play
|
* @param sound the sound to play
|
||||||
*/
|
*/
|
||||||
//% blockId=music_play_sound_effect block="play sound effect %sound"
|
//% blockId=music_play_sound_effect block="play sound effect %sound"
|
||||||
//% weight=99
|
//% weight=99 blockGap=8
|
||||||
export function playSoundEffect(sound: Sound) {
|
export function playSoundEffect(sound: Sound) {
|
||||||
if (!sound || numSoundsPlaying >= soundsLimit) return;
|
if (!sound || numSoundsPlaying >= soundsLimit) return;
|
||||||
numSoundsPlaying++;
|
numSoundsPlaying++;
|
||||||
|
35
libs/tests/README.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# tests
|
||||||
|
|
||||||
|
A unit test framework
|
||||||
|
|
||||||
|
## Defining tests
|
||||||
|
|
||||||
|
Tests are registered as event handlers. They will automatically run once ``on start`` is finished.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
tests.test("lgB set speed 10", () => {
|
||||||
|
motors.largeB.setSpeed(10);
|
||||||
|
loops.pause(100)
|
||||||
|
tests.assertClose("speedB", 10, motors.largeB.speed(), 2)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Assertions
|
||||||
|
|
||||||
|
The library has various asserts that will register fault. Note that since exceptions are not available, assertion failure **do not** stop the program execution.
|
||||||
|
|
||||||
|
* **assert** checks a boolean condition
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
tests.assert("speed positive", motors.largeB.speed() > 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
* **assert close** checks that a numberical value is within a particular range
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
tests.assertClose("speed", motors.largeB.speed(), 10, 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
```package
|
||||||
|
tests
|
||||||
|
```
|
11
libs/tests/_locales/tests-jsdoc-strings.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"TestEvent": "Various test event in the execution cycle",
|
||||||
|
"tests": "A Unit tests framework",
|
||||||
|
"tests.assert": "Checks a boolean condition",
|
||||||
|
"tests.assertClose": "Checks that 2 values are close to each other",
|
||||||
|
"tests.assertClose|param|actual": "what the value was",
|
||||||
|
"tests.assertClose|param|expected": "what the value should be",
|
||||||
|
"tests.assertClose|param|tolerance": "the acceptable error margin, eg: 5",
|
||||||
|
"tests.onEvent": "Registers code to be called at various points in the test execution",
|
||||||
|
"tests.test": "Registers a test to run"
|
||||||
|
}
|
11
libs/tests/_locales/tests-strings.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"TestEvent.RunSetUp|block": "run setup",
|
||||||
|
"TestEvent.RunTearDown|block": "run teardown",
|
||||||
|
"TestEvent.TestSetUp|block": "test setup",
|
||||||
|
"TestEvent.TestTearDown|block": "test teardown",
|
||||||
|
"tests.assertClose|block": "assert %message|%expected|close to %actual|by %tolerance",
|
||||||
|
"tests.assert|block": "assert %message|%condition",
|
||||||
|
"tests.test|block": "test %name",
|
||||||
|
"tests|block": "tests",
|
||||||
|
"{id:category}Tests": "Tests"
|
||||||
|
}
|
12
libs/tests/platformoverrides.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// EV3 specific test functions
|
||||||
|
tests.onEvent(TestEvent.RunSetUp, function() {
|
||||||
|
console.sendToScreen();
|
||||||
|
})
|
||||||
|
tests.onEvent(TestEvent.TestSetUp, function() {
|
||||||
|
motors.stopAllMotors();
|
||||||
|
motors.resetAllMotors();
|
||||||
|
})
|
||||||
|
tests.onEvent(TestEvent.TestTearDown, function() {
|
||||||
|
motors.stopAllMotors();
|
||||||
|
motors.resetAllMotors();
|
||||||
|
})
|
16
libs/tests/pxt.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "tests",
|
||||||
|
"description": "A unit test library",
|
||||||
|
"files": [
|
||||||
|
"README.md",
|
||||||
|
"tests.ts",
|
||||||
|
"platformoverrides.ts"
|
||||||
|
],
|
||||||
|
"testFiles": [
|
||||||
|
],
|
||||||
|
"public": true,
|
||||||
|
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/tests",
|
||||||
|
"dependencies": {
|
||||||
|
"core": "file:../core"
|
||||||
|
}
|
||||||
|
}
|
@ -2,14 +2,14 @@
|
|||||||
"TouchSensorEvent.Bumped|block": "bumped",
|
"TouchSensorEvent.Bumped|block": "bumped",
|
||||||
"TouchSensorEvent.Pressed|block": "pressed",
|
"TouchSensorEvent.Pressed|block": "pressed",
|
||||||
"TouchSensorEvent.Released|block": "released",
|
"TouchSensorEvent.Released|block": "released",
|
||||||
"sensors.TouchSensor.isPressed|block": "`icons.touchSensor` %sensor|is pressed",
|
"sensors.TouchSensor.isPressed|block": "%sensor|is pressed",
|
||||||
"sensors.TouchSensor.onEvent|block": "on `icons.touchSensor` %sensor|%event",
|
"sensors.TouchSensor.onEvent|block": "on %sensor|%event",
|
||||||
"sensors.TouchSensor.pauseUntil|block": "pause until `icons.touchSensor` %sensor|%event",
|
"sensors.TouchSensor.pauseUntil|block": "pause until %sensor|%event",
|
||||||
"sensors.TouchSensor.wasPressed|block": "`icons.touchSensor` %sensor|was pressed",
|
"sensors.TouchSensor.wasPressed|block": "%sensor|was pressed",
|
||||||
"sensors.touchSensor1|block": "1",
|
"sensors.touchSensor1|block": "touch 1",
|
||||||
"sensors.touchSensor2|block": "2",
|
"sensors.touchSensor2|block": "touch 2",
|
||||||
"sensors.touchSensor3|block": "3",
|
"sensors.touchSensor3|block": "touch 3",
|
||||||
"sensors.touchSensor4|block": "4",
|
"sensors.touchSensor4|block": "touch 4",
|
||||||
"{id:category}Sensors": "Sensors",
|
"{id:category}Sensors": "Sensors",
|
||||||
"{id:group}Touch Sensor": "Touch Sensor"
|
"{id:group}Touch Sensor": "Touch Sensor"
|
||||||
}
|
}
|
@ -42,11 +42,10 @@ namespace sensors {
|
|||||||
* @param body code to run when the event is raised
|
* @param body code to run when the event is raised
|
||||||
*/
|
*/
|
||||||
//% help=input/touch-sensor/on-event
|
//% help=input/touch-sensor/on-event
|
||||||
//% blockId=touchEvent block="on `icons.touchSensor` %sensor|%event"
|
//% blockId=touchEvent block="on %sensor|%event"
|
||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
onEvent(ev: TouchSensorEvent, body: () => void) {
|
onEvent(ev: TouchSensorEvent, body: () => void) {
|
||||||
@ -59,11 +58,10 @@ namespace sensors {
|
|||||||
* @param event the kind of button gesture that needs to be detected
|
* @param event the kind of button gesture that needs to be detected
|
||||||
*/
|
*/
|
||||||
//% help=input/touch-sensor/pause-until
|
//% help=input/touch-sensor/pause-until
|
||||||
//% blockId=touchWaitUntil block="pause until `icons.touchSensor` %sensor|%event"
|
//% blockId=touchWaitUntil block="pause until %sensor|%event"
|
||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=98 blockGap=8
|
//% weight=98 blockGap=8
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
pauseUntil(ev: TouchSensorEvent) {
|
pauseUntil(ev: TouchSensorEvent) {
|
||||||
@ -75,13 +73,12 @@ namespace sensors {
|
|||||||
* @param sensor the port to query the request
|
* @param sensor the port to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/touch-sensor/is-pressed
|
//% help=input/touch-sensor/is-pressed
|
||||||
//% block="`icons.touchSensor` %sensor|is pressed"
|
//% block="%sensor|is pressed"
|
||||||
//% blockId=touchIsPressed
|
//% blockId=touchIsPressed
|
||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=81 blockGap=8
|
//% sensor.fieldEditor="ports"
|
||||||
|
//% weight=81
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
isPressed() {
|
isPressed() {
|
||||||
return this.button.isPressed();
|
return this.button.isPressed();
|
||||||
@ -92,12 +89,11 @@ namespace sensors {
|
|||||||
* @param sensor the port to query the request
|
* @param sensor the port to query the request
|
||||||
*/
|
*/
|
||||||
//% help=input/touch-sensor/was-pressed
|
//% help=input/touch-sensor/was-pressed
|
||||||
//% block="`icons.touchSensor` %sensor|was pressed"
|
//% block="%sensor|was pressed"
|
||||||
//% blockId=touchWasPressed
|
//% blockId=touchWasPressed
|
||||||
//% parts="touch"
|
//% parts="touch"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=81 blockGap=8
|
//% weight=81 blockGap=8
|
||||||
//% group="Touch Sensor"
|
//% group="Touch Sensor"
|
||||||
wasPressed() {
|
wasPressed() {
|
||||||
@ -105,12 +101,12 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% whenUsed block="1" weight=95 fixedInstance jres=icons.port1
|
//% whenUsed block="touch 1" weight=95 fixedInstance jres=icons.port1
|
||||||
export const touchSensor1: TouchSensor = new TouchSensor(1)
|
export const touchSensor1: TouchSensor = new TouchSensor(1)
|
||||||
//% whenUsed block="2" weight=95 fixedInstance jres=icons.port2
|
//% whenUsed block="touch 2" weight=95 fixedInstance jres=icons.port2
|
||||||
export const touchSensor2: TouchSensor = new TouchSensor(2)
|
export const touchSensor2: TouchSensor = new TouchSensor(2)
|
||||||
//% whenUsed block="3" weight=95 fixedInstance jres=icons.port3
|
//% whenUsed block="touch 3" weight=95 fixedInstance jres=icons.port3
|
||||||
export const touchSensor3: TouchSensor = new TouchSensor(3)
|
export const touchSensor3: TouchSensor = new TouchSensor(3)
|
||||||
//% whenUsed block="4" weight=95 fixedInstance jres=icons.port4
|
//% whenUsed block="touch 4" weight=95 fixedInstance jres=icons.port4
|
||||||
export const touchSensor4: TouchSensor = new TouchSensor(4)
|
export const touchSensor4: TouchSensor = new TouchSensor(4)
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
"UltrasonicSensorEvent.ObjectDetected|block": "object detected",
|
"UltrasonicSensorEvent.ObjectDetected|block": "object detected",
|
||||||
"UltrasonicSensorEvent.ObjectFar|block": "object far",
|
"UltrasonicSensorEvent.ObjectFar|block": "object far",
|
||||||
"UltrasonicSensorEvent.ObjectNear|block": "object near",
|
"UltrasonicSensorEvent.ObjectNear|block": "object near",
|
||||||
"sensors.UltraSonicSensor.distance|block": "`icons.ultrasonicSensor` %sensor|distance",
|
"sensors.UltraSonicSensor.distance|block": "%sensor|distance",
|
||||||
"sensors.UltraSonicSensor.onEvent|block": "on `icons.ultrasonicSensor` %sensor|%event",
|
"sensors.UltraSonicSensor.onEvent|block": "on %sensor|%event",
|
||||||
"sensors.UltraSonicSensor.pauseUntil|block": "pause until `icons.ultrasonicSensor` %sensor| %event",
|
"sensors.UltraSonicSensor.pauseUntil|block": "pause until %sensor| %event",
|
||||||
"sensors.ultrasonic1|block": "1",
|
"sensors.ultrasonic1|block": "ultrasonic 1",
|
||||||
"sensors.ultrasonic2|block": "2",
|
"sensors.ultrasonic2|block": "ultrasonic 2",
|
||||||
"sensors.ultrasonic3|block": "3",
|
"sensors.ultrasonic3|block": "ultrasonic 3",
|
||||||
"sensors.ultrasonic4|block": "4",
|
"sensors.ultrasonic4|block": "ultrasonic 4",
|
||||||
"{id:category}Sensors": "Sensors",
|
"{id:category}Sensors": "Sensors",
|
||||||
"{id:group}Ultrasonic Sensor": "Ultrasonic Sensor"
|
"{id:group}Ultrasonic Sensor": "Ultrasonic Sensor"
|
||||||
}
|
}
|
@ -25,7 +25,7 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_query(): number {
|
_query(): number {
|
||||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
return ((this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff) / 10) >> 0; // range is 0..2550, in 0.1 cm increments.
|
||||||
}
|
}
|
||||||
|
|
||||||
_update(prev: number, curr: number) {
|
_update(prev: number, curr: number) {
|
||||||
@ -43,11 +43,10 @@ namespace sensors {
|
|||||||
*/
|
*/
|
||||||
//% help=input/ultrasonic/on
|
//% help=input/ultrasonic/on
|
||||||
//% blockId=ultrasonicOn
|
//% blockId=ultrasonicOn
|
||||||
//% block="on `icons.ultrasonicSensor` %sensor|%event"
|
//% block="on %sensor|%event"
|
||||||
//% parts="ultrasonicsensor"
|
//% parts="ultrasonicsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=100 blockGap=8
|
//% weight=100 blockGap=8
|
||||||
//% group="Ultrasonic Sensor"
|
//% group="Ultrasonic Sensor"
|
||||||
onEvent(event: UltrasonicSensorEvent, handler: () => void) {
|
onEvent(event: UltrasonicSensorEvent, handler: () => void) {
|
||||||
@ -58,12 +57,11 @@ namespace sensors {
|
|||||||
* Waits for the event to occur
|
* Waits for the event to occur
|
||||||
*/
|
*/
|
||||||
//% help=input/ultrasonic/wait
|
//% help=input/ultrasonic/wait
|
||||||
//% block="pause until `icons.ultrasonicSensor` %sensor| %event"
|
//% block="pause until %sensor| %event"
|
||||||
//% blockId=ultrasonicWait
|
//% blockId=ultrasonicWait
|
||||||
//% parts="ultrasonicsensor"
|
//% parts="ultrasonicsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
|
//% sensor.fieldEditor="ports"
|
||||||
//% weight=99 blockGap=8
|
//% weight=99 blockGap=8
|
||||||
//% group="Ultrasonic Sensor"
|
//% group="Ultrasonic Sensor"
|
||||||
pauseUntil(event: UltrasonicSensorEvent) {
|
pauseUntil(event: UltrasonicSensorEvent) {
|
||||||
@ -75,30 +73,29 @@ namespace sensors {
|
|||||||
* @param sensor the ultrasonic sensor port
|
* @param sensor the ultrasonic sensor port
|
||||||
*/
|
*/
|
||||||
//% help=input/ultrasonic/distance
|
//% help=input/ultrasonic/distance
|
||||||
//% block="`icons.ultrasonicSensor` %sensor|distance"
|
//% block="%sensor|distance"
|
||||||
//% blockId=sonarGetDistance
|
//% blockId=sonarGetDistance
|
||||||
//% parts="ultrasonicsensor"
|
//% parts="ultrasonicsensor"
|
||||||
//% sensor.fieldEditor="imagedropdown"
|
|
||||||
//% sensor.fieldOptions.columns=4
|
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% weight=65 blockGap=8
|
//% sensor.fieldEditor="ports"
|
||||||
|
//% weight=65
|
||||||
//% group="Ultrasonic Sensor"
|
//% group="Ultrasonic Sensor"
|
||||||
distance(): number {
|
distance(): number {
|
||||||
// it supposedly also has an inch mode, but we stick to cm
|
// it supposedly also has an inch mode, but we stick to cm
|
||||||
this._setMode(0)
|
this._setMode(0)
|
||||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff; // range is 0..255
|
return this._query();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="1" jres=icons.port1
|
//% fixedInstance whenUsed block="ultrasonic 1" jres=icons.port1
|
||||||
export const ultrasonic1: UltraSonicSensor = new UltraSonicSensor(1)
|
export const ultrasonic1: UltraSonicSensor = new UltraSonicSensor(1)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="2" jres=icons.port2
|
//% fixedInstance whenUsed block="ultrasonic 2" jres=icons.port2
|
||||||
export const ultrasonic2: UltraSonicSensor = new UltraSonicSensor(2)
|
export const ultrasonic2: UltraSonicSensor = new UltraSonicSensor(2)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="3" jres=icons.port3
|
//% fixedInstance whenUsed block="ultrasonic 3" jres=icons.port3
|
||||||
export const ultrasonic3: UltraSonicSensor = new UltraSonicSensor(3)
|
export const ultrasonic3: UltraSonicSensor = new UltraSonicSensor(3)
|
||||||
|
|
||||||
//% fixedInstance whenUsed block="4" jres=icons.port4
|
//% fixedInstance whenUsed block="ultrasonic 4" jres=icons.port4
|
||||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||||
}
|
}
|
||||||
|
4683
package-lock.json
generated
Normal file
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "0.0.42",
|
"version": "0.0.51",
|
||||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||||
"private": true,
|
"private": true,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -44,8 +44,8 @@
|
|||||||
"webfonts-generator": "^0.4.0"
|
"webfonts-generator": "^0.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pxt-common-packages": "0.14.13",
|
"pxt-common-packages": "0.15.1",
|
||||||
"pxt-core": "3.0.2"
|
"pxt-core": "3.0.5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
"libs/ultrasonic-sensor",
|
"libs/ultrasonic-sensor",
|
||||||
"libs/infrared-sensor",
|
"libs/infrared-sensor",
|
||||||
"libs/gyro-sensor",
|
"libs/gyro-sensor",
|
||||||
"libs/ev3"
|
"libs/ev3",
|
||||||
|
"libs/tests"
|
||||||
],
|
],
|
||||||
"simulator": {
|
"simulator": {
|
||||||
"autoRun": true,
|
"autoRun": true,
|
||||||
@ -52,8 +53,10 @@
|
|||||||
"serial": {
|
"serial": {
|
||||||
"vendorId": "0x0694",
|
"vendorId": "0x0694",
|
||||||
"productId": "0x0005",
|
"productId": "0x0005",
|
||||||
"rawHID": true
|
"rawHID": true,
|
||||||
},
|
"useEditor": true,
|
||||||
|
"log": true
|
||||||
|
},
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"mathBlocks": true,
|
"mathBlocks": true,
|
||||||
"loopsBlocks": true,
|
"loopsBlocks": true,
|
||||||
@ -91,6 +94,7 @@
|
|||||||
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
||||||
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
||||||
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
||||||
|
"betaUrl": "https://lego.makecode.com/",
|
||||||
"boardName": "LEGO Mindstorms EV3 Brick",
|
"boardName": "LEGO Mindstorms EV3 Brick",
|
||||||
"selectLanguage": true,
|
"selectLanguage": true,
|
||||||
"highContrast": true,
|
"highContrast": true,
|
||||||
@ -129,16 +133,23 @@
|
|||||||
"logic": "#1E5AA8",
|
"logic": "#1E5AA8",
|
||||||
"math": "#9DC3F7",
|
"math": "#9DC3F7",
|
||||||
"variables": "#B40000",
|
"variables": "#B40000",
|
||||||
"text": "#F0890A",
|
"text": "#FCAC00",
|
||||||
"advanced": "#969696",
|
"advanced": "#969696",
|
||||||
"functions": "#064597",
|
"functions": "#19325A",
|
||||||
"arrays": "#890058"
|
"arrays": "#901F76"
|
||||||
|
},
|
||||||
|
"blockIcons": {
|
||||||
|
"loops": "\uf10b",
|
||||||
|
"logic": "\uf10a",
|
||||||
|
"math": "\uf10c",
|
||||||
|
"variables": "\uf111",
|
||||||
|
"text": "\uf110",
|
||||||
|
"functions": "\uf108",
|
||||||
|
"arrays": "\uf109"
|
||||||
},
|
},
|
||||||
"monacoColors": {
|
"monacoColors": {
|
||||||
"editor.background": "#ecf6ff"
|
"editor.background": "#ecf6ff"
|
||||||
},
|
}
|
||||||
"simAnimationEnter": "horizontal flip in",
|
|
||||||
"simAnimationExit": "horizontal flip out"
|
|
||||||
},
|
},
|
||||||
"ignoreDocsErrors": true
|
"ignoreDocsErrors": true
|
||||||
}
|
}
|
||||||
|
@ -23,20 +23,6 @@ namespace pxsim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class EV3Board extends CoreBoard {
|
export class EV3Board extends CoreBoard {
|
||||||
// state & update logic for component services
|
|
||||||
// neopixelState: CommonNeoPixelState;
|
|
||||||
buttonState: EV3ButtonState;
|
|
||||||
slideSwitchState: SlideSwitchState;
|
|
||||||
lightSensorState: AnalogSensorState;
|
|
||||||
thermometerState: AnalogSensorState;
|
|
||||||
thermometerUnitState: number;
|
|
||||||
microphoneState: AnalogSensorState;
|
|
||||||
edgeConnectorState: EdgeConnectorState;
|
|
||||||
capacitiveSensorState: CapacitiveSensorState;
|
|
||||||
accelerometerState: AccelerometerState;
|
|
||||||
touchButtonState: TouchButtonState;
|
|
||||||
irState: InfraredState;
|
|
||||||
|
|
||||||
view: SVGSVGElement;
|
view: SVGSVGElement;
|
||||||
|
|
||||||
outputState: EV3OutputState;
|
outputState: EV3OutputState;
|
||||||
@ -86,11 +72,6 @@ namespace pxsim {
|
|||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "irpacket": {
|
|
||||||
let ev = <SimulatorInfraredPacketMessage>msg;
|
|
||||||
this.irState.receive(new RefBuffer(ev.packet));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +101,9 @@ namespace pxsim {
|
|||||||
document.body.innerHTML = ""; // clear children
|
document.body.innerHTML = ""; // clear children
|
||||||
document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement);
|
document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement);
|
||||||
|
|
||||||
|
this.inputNodes = [];
|
||||||
|
this.outputNodes = [];
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,26 +111,33 @@ namespace pxsim {
|
|||||||
return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
|
return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
|
||||||
}
|
}
|
||||||
|
|
||||||
//defaultNeopixelPin() {
|
|
||||||
// return this.edgeConnectorState.getPin(CPlayPinName.D8);
|
|
||||||
//}
|
|
||||||
|
|
||||||
getDefaultPitchPin() {
|
|
||||||
return this.edgeConnectorState.getPin(CPlayPinName.D6);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBrickNode() {
|
getBrickNode() {
|
||||||
return this.brickNode;
|
return this.brickNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
motorUsed(port:number, large: boolean) {
|
||||||
|
for(let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||||
|
const p = 1 << i;
|
||||||
|
if (port & p) {
|
||||||
|
const motorPort = this.motorMap[p];
|
||||||
|
if (!this.outputNodes[motorPort])
|
||||||
|
this.outputNodes[motorPort] = new MotorNode(motorPort, large);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getMotor(port: number, large?: boolean): MotorNode[] {
|
getMotor(port: number, large?: boolean): MotorNode[] {
|
||||||
if (port == 0xFF) return this.getMotors(); // Return all motors
|
const r = [];
|
||||||
const motorPort = this.motorMap[port];
|
for(let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||||
if (this.outputNodes[motorPort] == undefined) {
|
const p = 1 << i;
|
||||||
this.outputNodes[motorPort] = large ?
|
if (port & p) {
|
||||||
new LargeMotorNode(motorPort) : new MediumMotorNode(motorPort);
|
const motorPort = this.motorMap[p];
|
||||||
|
const outputNode = this.outputNodes[motorPort];
|
||||||
|
if (outputNode)
|
||||||
|
r.push(outputNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return [this.outputNodes[motorPort]];
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMotors() {
|
getMotors() {
|
||||||
@ -154,7 +145,7 @@ namespace pxsim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSensor(port: number, type: number): SensorNode {
|
getSensor(port: number, type: number): SensorNode {
|
||||||
if (this.inputNodes[port] == undefined) {
|
if (!this.inputNodes[port]) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DAL.DEVICE_TYPE_GYRO: this.inputNodes[port] = new GyroSensorNode(port); break;
|
case DAL.DEVICE_TYPE_GYRO: this.inputNodes[port] = new GyroSensorNode(port); break;
|
||||||
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break;
|
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break;
|
||||||
|
@ -38,7 +38,7 @@ namespace pxsim {
|
|||||||
data[AnalogOff.InConn + port] = node.isUart() ? DAL.CONN_INPUT_UART : DAL.CONN_INPUT_DUMB;
|
data[AnalogOff.InConn + port] = node.isUart() ? DAL.CONN_INPUT_UART : DAL.CONN_INPUT_DUMB;
|
||||||
if (node.isAnalog() && node.hasData()) {
|
if (node.isAnalog() && node.hasData()) {
|
||||||
//data[AnalogOff.InPin6 + 2 * port] = node.getValue();
|
//data[AnalogOff.InPin6 + 2 * port] = node.getValue();
|
||||||
util.map16Bit(data, AnalogOff.InPin6 + 2 * port, node.getValue())
|
util.map16Bit(data, AnalogOff.InPin6 + 2 * port, Math.floor(node.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
namespace pxsim {
|
namespace pxsim {
|
||||||
|
|
||||||
export enum ColorSensorMode {
|
export enum ColorSensorMode {
|
||||||
|
None = -1,
|
||||||
Reflected = 0,
|
Reflected = 0,
|
||||||
Ambient = 1,
|
Ambient = 1,
|
||||||
Colors = 2,
|
Colors = 2,
|
||||||
RefRaw = 3,
|
RefRaw = 3,
|
||||||
RgbRaw = 4,
|
RgbRaw = 4,
|
||||||
ColorCal = 5
|
ColorCal = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ThresholdState {
|
export enum ThresholdState {
|
||||||
@ -20,23 +21,20 @@ namespace pxsim {
|
|||||||
export class ColorSensorNode extends UartSensorNode {
|
export class ColorSensorNode extends UartSensorNode {
|
||||||
id = NodeType.ColorSensor;
|
id = NodeType.ColorSensor;
|
||||||
|
|
||||||
private color: number;
|
private color: number = 50;
|
||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(port);
|
super(port);
|
||||||
|
this.mode = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeviceType() {
|
getDeviceType() {
|
||||||
return DAL.DEVICE_TYPE_COLOR;
|
return DAL.DEVICE_TYPE_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
setColor(color: number) {
|
setColor(color: number) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.changed = true;
|
this.setChangedState();
|
||||||
this.valueChanged = true;
|
|
||||||
|
|
||||||
runtime.queueDisplayUpdate();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue() {
|
getValue() {
|
||||||
|
@ -81,7 +81,6 @@ namespace pxsim.control {
|
|||||||
export function dmesg(s: string) {
|
export function dmesg(s: string) {
|
||||||
console.log("DMESG: " + s)
|
console.log("DMESG: " + s)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace pxsim.output {
|
namespace pxsim.output {
|
||||||
|
@ -22,20 +22,14 @@ namespace pxsim {
|
|||||||
setAngle(angle: number) {
|
setAngle(angle: number) {
|
||||||
if (this.angle != angle) {
|
if (this.angle != angle) {
|
||||||
this.angle = angle;
|
this.angle = angle;
|
||||||
this.changed = true;
|
this.setChangedState();
|
||||||
this.valueChanged = true;
|
|
||||||
|
|
||||||
runtime.queueDisplayUpdate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setRate(rate: number) {
|
setRate(rate: number) {
|
||||||
if (this.rate != rate) {
|
if (this.rate != rate) {
|
||||||
this.rate = rate;
|
this.rate = rate;
|
||||||
this.changed = true;
|
this.setChangedState();
|
||||||
this.valueChanged = true;
|
|
||||||
|
|
||||||
runtime.queueDisplayUpdate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
namespace pxsim.motors {
|
namespace pxsim.motors {
|
||||||
|
|
||||||
export function __motorUsed(port: number, large: boolean) {
|
export function __motorUsed(port: number, large: boolean) {
|
||||||
console.log("MOTOR INIT " + port);
|
//console.log("MOTOR INIT " + port);
|
||||||
const motors = ev3board().getMotor(port, large);
|
ev3board().motorUsed(port, large);
|
||||||
runtime.queueDisplayUpdate();
|
runtime.queueDisplayUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,7 +11,7 @@ namespace pxsim.motors {
|
|||||||
namespace pxsim.sensors {
|
namespace pxsim.sensors {
|
||||||
|
|
||||||
export function __sensorUsed(port: number, type: number) {
|
export function __sensorUsed(port: number, type: number) {
|
||||||
console.log("SENSOR INIT " + port + ", type: " + type);
|
//console.log("SENSOR INIT " + port + ", type: " + type);
|
||||||
const sensor = ev3board().getSensor(port, type);
|
const sensor = ev3board().getSensor(port, type);
|
||||||
runtime.queueDisplayUpdate();
|
runtime.queueDisplayUpdate();
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,11 @@ namespace pxsim {
|
|||||||
namespace pxsim.output {
|
namespace pxsim.output {
|
||||||
|
|
||||||
export function setLights(pattern: number) {
|
export function setLights(pattern: number) {
|
||||||
const lightState = ev3board().getBrickNode().lightState;
|
const brickState = ev3board().getBrickNode();
|
||||||
lightState.lightPattern = pattern;
|
const lightState = brickState.lightState;
|
||||||
runtime.queueDisplayUpdate();
|
if (lightState.lightPattern != pattern) {
|
||||||
|
lightState.lightPattern = pattern;
|
||||||
|
brickState.setChangedState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,11 +15,20 @@ namespace pxsim {
|
|||||||
MMapMethods.register("/dev/lms_motor", {
|
MMapMethods.register("/dev/lms_motor", {
|
||||||
data,
|
data,
|
||||||
beforeMemRead: () => {
|
beforeMemRead: () => {
|
||||||
console.log("motor before read");
|
const outputs = ev3board().outputNodes;
|
||||||
|
// console.log("motor before read");
|
||||||
for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) {
|
for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) {
|
||||||
data[MotorDataOff.TachoCounts * port] = 0; // Tacho count
|
const output = outputs[port];
|
||||||
data[MotorDataOff.Speed * port] = 50; // Speed
|
const speed = output ? outputs[port].getSpeed() : 0;
|
||||||
data[MotorDataOff.TachoSensor * port] = 0; // Count
|
const angle = output ? outputs[port].getAngle() : 0;
|
||||||
|
const tci = MotorDataOff.TachoCounts + port * MotorDataOff.Size;
|
||||||
|
const tsi = MotorDataOff.TachoSensor + port * MotorDataOff.Size;
|
||||||
|
data[tci] = data[tci + 1] = data[tci + 2] = data[tci + 3] = 0; // Tacho count
|
||||||
|
data[MotorDataOff.Speed + port * MotorDataOff.Size] = speed; // Speed
|
||||||
|
data[tsi] = angle & 0xff; // Count
|
||||||
|
data[tsi + 1] = (angle >> 8) & 0xff; // Count
|
||||||
|
data[tsi + 2] = (angle >> 16) & 0xff; // Count
|
||||||
|
data[tsi + 3] = (angle >> 24); // Count
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
read: buf => {
|
read: buf => {
|
||||||
|
182
sim/state/motornode.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
namespace pxsim {
|
||||||
|
|
||||||
|
export class MotorNode extends BaseNode {
|
||||||
|
isOutput = true;
|
||||||
|
private rotationsPerMilliSecond: number;
|
||||||
|
|
||||||
|
// current state
|
||||||
|
private angle: number = 0;
|
||||||
|
private tacho: number = 0;
|
||||||
|
private speed: number = 0;
|
||||||
|
private polarity: number = 1; // -1, 1 or -1
|
||||||
|
|
||||||
|
private started: boolean;
|
||||||
|
private speedCmd: DAL;
|
||||||
|
private speedCmdValues: number[];
|
||||||
|
private speedCmdTacho: number;
|
||||||
|
private speedCmdTime: number;
|
||||||
|
private _synchedMotor: MotorNode; // non-null if master motor
|
||||||
|
|
||||||
|
constructor(port: number, large: boolean) {
|
||||||
|
super(port);
|
||||||
|
this.setLarge(large);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSpeed() {
|
||||||
|
return this.speed * (this.polarity == 0 ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAngle() {
|
||||||
|
return this.angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the slave motor if any
|
||||||
|
getSynchedMotor() {
|
||||||
|
return this._synchedMotor;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSpeedCmd(cmd: DAL, values: number[]) {
|
||||||
|
this.speedCmd = cmd;
|
||||||
|
this.speedCmdValues = values;
|
||||||
|
this.speedCmdTacho = this.angle;
|
||||||
|
this.speedCmdTime = pxsim.U.now();
|
||||||
|
delete this._synchedMotor;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSyncCmd(motor: MotorNode, cmd: DAL, values: number[]) {
|
||||||
|
this.setSpeedCmd(cmd, values);
|
||||||
|
this._synchedMotor = motor;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSpeedCmd() {
|
||||||
|
delete this.speedCmd;
|
||||||
|
delete this._synchedMotor;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLarge(large: boolean) {
|
||||||
|
this.id = large ? NodeType.LargeMotor : NodeType.MediumMotor;
|
||||||
|
// large 170 rpm (https://education.lego.com/en-us/products/ev3-large-servo-motor/45502)
|
||||||
|
this.rotationsPerMilliSecond = (large ? 170 : 250) / 60000;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPolarity(polarity: number) {
|
||||||
|
// Either 1 or 255 (reverse)
|
||||||
|
/*
|
||||||
|
-1 : Motor will run backward
|
||||||
|
0 : Motor will run opposite direction
|
||||||
|
1 : Motor will run forward
|
||||||
|
*/
|
||||||
|
this.polarity = polarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
// not sure what reset does...
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCount() {
|
||||||
|
this.tacho = 0;
|
||||||
|
this.angle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.started = false;
|
||||||
|
this.clearSpeedCmd();
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState(elapsed: number) {
|
||||||
|
console.log(`motor: ${elapsed}ms - ${this.speed}% - ${this.angle}> - ${this.tacho}|`)
|
||||||
|
const interval = Math.min(20, elapsed);
|
||||||
|
let t = 0;
|
||||||
|
while (t < elapsed) {
|
||||||
|
let dt = interval;
|
||||||
|
if (t + dt > elapsed) dt = elapsed - t;
|
||||||
|
this.updateStateStep(dt);
|
||||||
|
t += dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateStateStep(elapsed: number) {
|
||||||
|
// compute new speed
|
||||||
|
switch (this.speedCmd) {
|
||||||
|
case DAL.opOutputSpeed:
|
||||||
|
case DAL.opOutputPower:
|
||||||
|
// assume power == speed
|
||||||
|
// TODO: PID
|
||||||
|
this.speed = this.speedCmdValues[0];
|
||||||
|
break;
|
||||||
|
case DAL.opOutputTimeSpeed:
|
||||||
|
case DAL.opOutputTimePower:
|
||||||
|
case DAL.opOutputStepPower:
|
||||||
|
case DAL.opOutputStepSpeed: {
|
||||||
|
// ramp up, run, ramp down, <brake> using time
|
||||||
|
const speed = this.speedCmdValues[0];
|
||||||
|
const step1 = this.speedCmdValues[1];
|
||||||
|
const step2 = this.speedCmdValues[2];
|
||||||
|
const step3 = this.speedCmdValues[3];
|
||||||
|
const brake = this.speedCmdValues[4];
|
||||||
|
const dstep = (this.speedCmd == DAL.opOutputTimePower || this.speedCmd == DAL.opOutputTimeSpeed)
|
||||||
|
? pxsim.U.now() - this.speedCmdTime
|
||||||
|
: this.tacho - this.speedCmdTacho;
|
||||||
|
if (dstep < step1) // rampup
|
||||||
|
this.speed = speed * dstep / step1;
|
||||||
|
else if (dstep < step1 + step2) // run
|
||||||
|
this.speed = speed;
|
||||||
|
else if (dstep < step1 + step2 + step3)
|
||||||
|
this.speed = speed * (step1 + step2 + step3 - dstep) / (step1 + step2 + step3);
|
||||||
|
else {
|
||||||
|
if (brake) this.speed = 0;
|
||||||
|
this.clearSpeedCmd();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DAL.opOutputStepSync:
|
||||||
|
case DAL.opOutputTimeSync: {
|
||||||
|
if (!this._synchedMotor) // handled in other motor code
|
||||||
|
break;
|
||||||
|
|
||||||
|
const otherMotor = this._synchedMotor;
|
||||||
|
const speed = this.speedCmdValues[0];
|
||||||
|
const turnRatio = this.speedCmdValues[1];
|
||||||
|
const stepsOrTime = this.speedCmdValues[2];
|
||||||
|
const brake = this.speedCmdValues[3];
|
||||||
|
const dstep = this.speedCmd == DAL.opOutputTimeSync
|
||||||
|
? pxsim.U.now() - this.speedCmdTime
|
||||||
|
: this.tacho - this.speedCmdTacho;
|
||||||
|
// 0 is special case, run infinite
|
||||||
|
if (!stepsOrTime || dstep < stepsOrTime)
|
||||||
|
this.speed = speed;
|
||||||
|
else {
|
||||||
|
if (brake) this.speed = 0;
|
||||||
|
this.clearSpeedCmd();
|
||||||
|
}
|
||||||
|
// send synched motor state
|
||||||
|
otherMotor.speed = Math.floor(this.speed * turnRatio / 100);
|
||||||
|
if (!this._synchedMotor)
|
||||||
|
otherMotor.clearSpeedCmd();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.speed = Math.round(this.speed); // integer only
|
||||||
|
|
||||||
|
// compute delta angle
|
||||||
|
const rotations = this.getSpeed() / 100 * this.rotationsPerMilliSecond * elapsed;
|
||||||
|
const deltaAngle = Math.round(rotations * 360);
|
||||||
|
if (deltaAngle) {
|
||||||
|
this.angle += deltaAngle;
|
||||||
|
this.tacho += Math.abs(deltaAngle);
|
||||||
|
this.setChangedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the motor was stopped or there are no speed commands,
|
||||||
|
// let it coast to speed 0
|
||||||
|
if (this.speed && !(this.started || this.speedCmd)) {
|
||||||
|
// decay speed 5% per tick
|
||||||
|
this.speed = Math.round(Math.max(0, Math.abs(this.speed) - 10) * Math.sign(this.speed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +0,0 @@
|
|||||||
namespace pxsim {
|
|
||||||
|
|
||||||
export class MotorNode extends BaseNode {
|
|
||||||
isOutput = true;
|
|
||||||
|
|
||||||
public angle: number = 0;
|
|
||||||
|
|
||||||
private speed: number;
|
|
||||||
private large: boolean;
|
|
||||||
private rotation: number;
|
|
||||||
private polarity: boolean;
|
|
||||||
|
|
||||||
constructor(port: number) {
|
|
||||||
super(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSpeed(speed: number) {
|
|
||||||
if (this.speed != speed) {
|
|
||||||
this.speed = speed;
|
|
||||||
this.changed = true;
|
|
||||||
runtime.queueDisplayUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setLarge(large: boolean) {
|
|
||||||
this.large = large;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSpeed() {
|
|
||||||
return this.speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
stepSpeed(speed: number, angle: number, brake: boolean) {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
setPolarity(polarity: number) {
|
|
||||||
// Either 1 or 255 (reverse)
|
|
||||||
this.polarity = polarity === 255;
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
// TODO: implement
|
|
||||||
runtime.queueDisplayUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MediumMotorNode extends MotorNode {
|
|
||||||
id = NodeType.MediumMotor;
|
|
||||||
|
|
||||||
constructor(port: number) {
|
|
||||||
super(port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LargeMotorNode extends MotorNode {
|
|
||||||
id = NodeType.LargeMotor;
|
|
||||||
|
|
||||||
constructor(port: number) {
|
|
||||||
super(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,5 +32,17 @@ namespace pxsim {
|
|||||||
this.changed = false;
|
this.changed = false;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setChangedState() {
|
||||||
|
this.changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates any internal state according to the elapsed time since the last call to `updateState`
|
||||||
|
* @param elapsed
|
||||||
|
*/
|
||||||
|
updateState(elapsed: number) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -34,24 +34,51 @@ namespace pxsim {
|
|||||||
motors.forEach(motor => motor.reset());
|
motors.forEach(motor => motor.reset());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
case DAL.opOutputStepSpeed: {
|
case DAL.opOutputClearCount:
|
||||||
|
const port = buf.data[1];
|
||||||
|
const motors = ev3board().getMotor(port);
|
||||||
|
motors.forEach(motor => motor.clearCount());
|
||||||
|
break;
|
||||||
|
case DAL.opOutputStepPower:
|
||||||
|
case DAL.opOutputStepSpeed:
|
||||||
|
case DAL.opOutputTimePower:
|
||||||
|
case DAL.opOutputTimeSpeed: {
|
||||||
// step speed
|
// step speed
|
||||||
const port = buf.data[1];
|
const port = buf.data[1];
|
||||||
const speed = buf.data[2];
|
const speed = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2); // signed byte
|
||||||
// note that b[3] is padding
|
// note that b[3] is padding
|
||||||
const step1 = buf.data[4];
|
const step1 = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 4);
|
||||||
const step2 = buf.data[5]; // angle
|
const step2 = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 8);
|
||||||
const step3 = buf.data[6];
|
const step3 = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 12);
|
||||||
const brake = buf.data[7];
|
const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 16);
|
||||||
//console.log(buf);
|
//console.log(buf);
|
||||||
const motors = ev3board().getMotor(port);
|
const motors = ev3board().getMotor(port);
|
||||||
motors.forEach(motor => motor.stepSpeed(speed, step2, brake === 1));
|
motors.forEach(motor => motor.setSpeedCmd(cmd, [speed, step1, step2, step3, brake]));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
case DAL.opOutputStepSync:
|
||||||
|
case DAL.opOutputTimeSync: {
|
||||||
|
const port = buf.data[1];
|
||||||
|
const speed = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2); // signed byte
|
||||||
|
// note that b[3] is padding
|
||||||
|
const turnRatio = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int16LE, 4);
|
||||||
|
// b[6], b[7] is padding
|
||||||
|
const stepsOrTime = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 8);
|
||||||
|
const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 12);
|
||||||
|
|
||||||
|
const motors = ev3board().getMotor(port);
|
||||||
|
for (const motor of motors) {
|
||||||
|
const otherMotor = motors.filter(m => m.port != motor.port)[0];
|
||||||
|
motor.setSyncCmd(
|
||||||
|
motor.port < otherMotor.port ? otherMotor : undefined,
|
||||||
|
cmd, [speed, turnRatio, stepsOrTime, brake]);
|
||||||
|
}
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
case DAL.opOutputStop: {
|
case DAL.opOutputStop: {
|
||||||
// stop
|
// stop
|
||||||
const port = buf.data[1];
|
const port = buf.data[1];
|
||||||
const brake = buf.data[2];
|
const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
|
||||||
const motors = ev3board().getMotor(port);
|
const motors = ev3board().getMotor(port);
|
||||||
motors.forEach(motor => motor.stop());
|
motors.forEach(motor => motor.stop());
|
||||||
return 2;
|
return 2;
|
||||||
@ -59,9 +86,9 @@ namespace pxsim {
|
|||||||
case DAL.opOutputSpeed: {
|
case DAL.opOutputSpeed: {
|
||||||
// setSpeed
|
// setSpeed
|
||||||
const port = buf.data[1];
|
const port = buf.data[1];
|
||||||
const speed = buf.data[2];
|
const speed = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
|
||||||
const motors = ev3board().getMotor(port);
|
const motors = ev3board().getMotor(port);
|
||||||
motors.forEach(motor => motor.setSpeed(speed));
|
motors.forEach(motor => motor.setSpeedCmd(cmd, [speed]));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
case DAL.opOutputStart: {
|
case DAL.opOutputStart: {
|
||||||
@ -74,7 +101,7 @@ namespace pxsim {
|
|||||||
case DAL.opOutputPolarity: {
|
case DAL.opOutputPolarity: {
|
||||||
// reverse
|
// reverse
|
||||||
const port = buf.data[1];
|
const port = buf.data[1];
|
||||||
const polarity = buf.data[2];
|
const polarity = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
|
||||||
const motors = ev3board().getMotor(port);
|
const motors = ev3board().getMotor(port);
|
||||||
motors.forEach(motor => motor.setPolarity(polarity));
|
motors.forEach(motor => motor.setPolarity(polarity));
|
||||||
return 2;
|
return 2;
|
||||||
@ -86,6 +113,9 @@ namespace pxsim {
|
|||||||
motors.forEach(motor => motor.setLarge(large));
|
motors.forEach(motor => motor.setLarge(large));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
console.warn('unknown cmd: ' + cmd);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("pwm write");
|
console.log("pwm write");
|
||||||
|
@ -7,6 +7,7 @@ namespace pxsim {
|
|||||||
|
|
||||||
|
|
||||||
export class EV3ScreenState {
|
export class EV3ScreenState {
|
||||||
|
changed: boolean = true;
|
||||||
points: Uint8Array;
|
points: Uint8Array;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
|
this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
|
||||||
@ -23,13 +24,13 @@ namespace pxsim {
|
|||||||
|
|
||||||
setPixel(x: number, y: number, v: number) {
|
setPixel(x: number, y: number, v: number) {
|
||||||
this.applyMode(OFF(x, y), v)
|
this.applyMode(OFF(x, y), v)
|
||||||
runtime.queueDisplayUpdate();
|
this.changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
for (let i = 0; i < this.points.length; ++i)
|
for (let i = 0; i < this.points.length; ++i)
|
||||||
this.points[i] = 0;
|
this.points[i] = 0;
|
||||||
runtime.queueDisplayUpdate();
|
this.changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
|
blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
|
||||||
@ -58,7 +59,7 @@ namespace pxsim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.queueDisplayUpdate();
|
this.changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearLine(x: number, y: number, w: number) {
|
clearLine(x: number, y: number, w: number) {
|
||||||
@ -72,6 +73,12 @@ namespace pxsim {
|
|||||||
off++
|
off++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
didChange() {
|
||||||
|
const res = this.changed;
|
||||||
|
this.changed = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ namespace pxsim {
|
|||||||
|
|
||||||
protected mode: number;
|
protected mode: number;
|
||||||
protected valueChanged: boolean;
|
protected valueChanged: boolean;
|
||||||
|
protected modeChanged: boolean;
|
||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(port);
|
super(port);
|
||||||
@ -24,6 +25,8 @@ namespace pxsim {
|
|||||||
|
|
||||||
setMode(mode: number) {
|
setMode(mode: number) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
this.changed = true;
|
||||||
|
this.modeChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMode() {
|
getMode() {
|
||||||
@ -43,6 +46,17 @@ namespace pxsim {
|
|||||||
this.valueChanged = false;
|
this.valueChanged = false;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modeChange() {
|
||||||
|
const res = this.modeChanged;
|
||||||
|
this.modeChanged = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
setChangedState() {
|
||||||
|
this.changed = true;
|
||||||
|
this.valueChanged = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnalogSensorNode extends SensorNode {
|
export class AnalogSensorNode extends SensorNode {
|
||||||
|
@ -14,8 +14,7 @@ namespace pxsim {
|
|||||||
|
|
||||||
public setPressed(pressed: boolean) {
|
public setPressed(pressed: boolean) {
|
||||||
this.pressed.push(pressed);
|
this.pressed.push(pressed);
|
||||||
this.changed = true;
|
this.setChangedState();
|
||||||
this.valueChanged = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPressed() {
|
public isPressed() {
|
||||||
|
@ -88,10 +88,10 @@ namespace pxsim {
|
|||||||
const inputNodes = ev3board().getInputNodes();
|
const inputNodes = ev3board().getInputNodes();
|
||||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||||
const node = inputNodes[port];
|
const node = inputNodes[port];
|
||||||
if (node) {
|
if (node && node.isUart()) {
|
||||||
// Actual
|
// Actual
|
||||||
const index = 0; //UartOff.Actual + port * 2;
|
const index = 0; //UartOff.Actual + port * 2;
|
||||||
data[UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index] = node.getValue();
|
util.map16Bit(data, UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index, Math.floor(node.getValue()))
|
||||||
// Status
|
// Status
|
||||||
data[UartOff.Status + port] = node.valueChange() ? UartStatus.UART_PORT_CHANGED : UartStatus.UART_DATA_READY;
|
data[UartOff.Status + port] = node.valueChange() ? UartStatus.UART_PORT_CHANGED : UartStatus.UART_DATA_READY;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ namespace pxsim {
|
|||||||
export class UltrasonicSensorNode extends UartSensorNode {
|
export class UltrasonicSensorNode extends UartSensorNode {
|
||||||
id = NodeType.UltrasonicSensor;
|
id = NodeType.UltrasonicSensor;
|
||||||
|
|
||||||
private distance: number = 50;
|
private distance: number = 127; // in cm
|
||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(port);
|
super(port);
|
||||||
@ -17,15 +17,12 @@ namespace pxsim {
|
|||||||
setDistance(distance: number) {
|
setDistance(distance: number) {
|
||||||
if (this.distance != distance) {
|
if (this.distance != distance) {
|
||||||
this.distance = distance;
|
this.distance = distance;
|
||||||
this.changed = true;
|
this.setChangedState();
|
||||||
this.valueChanged = true;
|
|
||||||
|
|
||||||
runtime.queueDisplayUpdate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue() {
|
getValue() {
|
||||||
return this.distance;
|
return this.distance * 10; // convert to 0.1 cm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
namespace pxsim.util {
|
namespace pxsim.util {
|
||||||
|
|
||||||
export function map16Bit(buffer: Uint8Array, index: number, value: number) {
|
export function map16Bit(buffer: Uint8Array, index: number, value: number) {
|
||||||
buffer[index] = (value >> 8) & 0xff;
|
buffer[index] = value & 0xFF;
|
||||||
buffer[index+1] = value & 0xff;
|
buffer[index + 1] = (value >> 8) & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,69 +1,87 @@
|
|||||||
<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61">
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 82 156">
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872">
|
<clipPath id="clip-path" transform="translate(0.98 1.9)">
|
||||||
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/>
|
<path d="M79,17.05A17.07,17.07,0,0,1,64.92,33.86l.36.39V70c0,.42-.14.4-.39.68L54,81.22v10l.75.78v.79h6.79a4,4,0,0,1,4,4v25.82a4,4,0,0,1-4,4H54.75v8.18A5.79,5.79,0,0,1,49,140.61h-6.5v7.57a4,4,0,0,1-2.9,3.84v1a.6.6,0,0,1-.6.6H12.69a.6.6,0,0,1-.6-.6h0v-1.29a4,4,0,0,1-2.17-3.55v-7.57H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59l13.68.1,0-11.8H26a4,4,0,0,1-4-4V39.79a4,4,0,0,1,4-4h6.78l0-11.77c0-.84.15-.84.46-1.14l10.41-10.1.22-.19a1.53,1.53,0,0,1,1.59.23A17.07,17.07,0,0,1,79,17.05Z" style="fill: none"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e">
|
<clipPath id="clip-path-2" transform="translate(0.98 1.9)">
|
||||||
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
<path d="M49,140.61H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59s19.46.14,23.87.14a2.27,2.27,0,0,1,2.37,1L54.75,92v42.79A5.79,5.79,0,0,1,49,140.61Z" style="fill: none"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927">
|
<clipPath id="clip-path-3" transform="translate(0.98 1.9)">
|
||||||
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/>
|
<path d="M43.18,135.24H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.21C15,95.94,21.86,86.8,21.86,86.8H43.18A5.78,5.78,0,0,1,49,92.58h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
<title>Large Motor</title>
|
<title>Large Motor</title>
|
||||||
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)">
|
<g style="isolation: isolate">
|
||||||
<g>
|
<g id="e13b39e7-895d-4931-9be9-7aecaf709784">
|
||||||
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/>
|
<g style="clip-path: url(#clip-path)">
|
||||||
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/>
|
<g id="Large_Motor" data-name="Large Motor">
|
||||||
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
|
<path id="LM_back2" data-name="LM back2" d="M39,153.62H12.69a.6.6,0,0,1-.6-.6h0v-5.3a.6.6,0,0,1,.6-.6H39a.6.6,0,0,1,.6.6V153A.6.6,0,0,1,39,153.62Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
|
<g>
|
||||||
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
|
<image width="36" height="20" transform="translate(9 136)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAVCAYAAADB5CeuAAAACXBIWXMAAAsSAAALEgHS3X78AAAAp0lEQVRIS+3WsW3DMBBG4Y+GSmcGp/cAHsuzeIasFPdWVpD6c0FKcBWwOxV8wIEgSIAPvOL+EhFKKcUBiIiAgjO+25rJildErJMqdMdVlcwg8MQDv5P6Q1fc5ErRujW1TfmoLPa3T//dymJI9TKkehlSvQypXoZUL5vUNhAz2R1Oao75w9IOMmpRHVZqSpjxo3KRw+YwQ2lx+EsVykqfK+aIWGhSR+MNDy9ID5XUCOsAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
|
<path id="LM_back1-2" data-name="LM back1-2" d="M41.86,152.17H10.53a.6.6,0,0,1-.6-.6v-14.7a.6.6,0,0,1,.6-.6H41.86a.6.6,0,0,1,.6.6h0v14.7A.6.6,0,0,1,41.86,152.17Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
|
|
||||||
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
|
|
||||||
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
|
|
||||||
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
|
|
||||||
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
|
|
||||||
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
|
|
||||||
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
|
|
||||||
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
|
|
||||||
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
|
|
||||||
</g>
|
|
||||||
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/>
|
|
||||||
<g>
|
|
||||||
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03">
|
|
||||||
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)">
|
|
||||||
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153">
|
|
||||||
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
</g>
|
||||||
</g>
|
<g id="LM_rightside" data-name="LM rightside">
|
||||||
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
|
<path id="LM_rightside5" data-name="LM rightside5" d="M33.08,69.61H27.47A5.45,5.45,0,0,1,22,64.15h0V41.25a5.45,5.45,0,0,1,5.46-5.46h5.61a5.46,5.46,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,33.08,69.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
|
<circle id="LM_rightside4" data-name="LM rightside4" cx="28.3" cy="66.21" r="3.79" style="fill: #fff"/>
|
||||||
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
|
<circle id="LM_rightside3" data-name="LM rightside3" cx="28.3" cy="43" r="3.79" style="fill: #fff"/>
|
||||||
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
|
<path id="LM_rightside2" data-name="LM rightside2" d="M24.4,59.69A4.16,4.16,0,0,1,26.74,59a5.23,5.23,0,0,1,3,.71c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.85-1.23-.46l-1,.58s-.36.19-.36-.33V55s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.39-.29-1.32-.29-1.32H29.1s-.73,0-.73-.65v-1.3s-.23-.36-1.17-.3a3.56,3.56,0,0,0-1.4.3v1.3a.66.66,0,0,1-.66.65c-.63,0-1.26,0-1.26,0s-.25.19-.29,1.32.29,1.39.29,1.39h1.26s.8.05.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.41-.82.46,0,1.8,0,1.8S23.67,60.12,24.4,59.69Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
|
<path id="LM_rightside1" data-name="LM rightside1" d="M31.25,47.89a.84.84,0,0,1-1,.68.85.85,0,0,1-.24-.09,6.63,6.63,0,0,0-2.85-.77,5.11,5.11,0,0,0-2.77.77c-.83.4-1.07-.59-1.07-.59V46.13a.72.72,0,0,1,.76-.66.67.67,0,0,1,.31.1,5.79,5.79,0,0,0,2.77.84,7.12,7.12,0,0,0,2.85-.84s1.18-.24,1.2.56S31.25,47.89,31.25,47.89Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
|
</g>
|
||||||
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
|
<g>
|
||||||
|
<image width="36" height="76" transform="translate(32 12)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAABNCAYAAAAhOa00AAAACXBIWXMAAAsSAAALEgHS3X78AAACAElEQVRoQ+3avVHDMBiA4VdcypgREmo4RggLpKKHAZiIAWgoKZggrEAGCBsQpxeFpNgJ/vkkK5YLvXe6g2Cb53zE9oVPaa3xSSmlALTvjh4pn2MrpQpgab/dAYdL4MQoC3oAnuxLH8AW2Gmty9YdAxKhaqAXYAUozJnaAm/AJiZs1rfBGegBKOyP7oAFMLfbRYN1ojpAYM7WtX3dbR8F1orqAdVz27n9BsMaUR4gV1yY1vpkYX7BGvgE9oD2WL/AO3CPfROFrKs6MOAMnVcAt3b57lsV6QzV194eYw0UfWelacUGRYFdAjQYNsPcy54xV+rwv4P/Bb8jZ5gr8oK4IFcQzF2nVOdWw/KG9d77IuUFGwsFHrAxUSCEjY0CASwFCnpgqVDQAUuJghZYahQY2Ao4YJ77v08eXRJWUHvenwoKaneVKaGOZZS0jJKWUdIySlpGScsoaRklLaOkZZS0jJKWUdIySlpGScsoaRklLaOkTQml3RdTQZXAD+bD2EmgSuALMwmyg/SoEtgAr9RGU1KiGkGQDtUKgjSoThCMj+oFwbgoEQjGQ4lBMA7KCwSXR3mDoPonpBsFccWYUwgCgUEdMAN/YDBzzKjJvG0nQe7W4Q2CCnFDhVgCj1TznCHtGDDVqLTWxylXW4wzdWDA/GfjnOcZMijddGBhouHTsfsDst/cEY24RzwAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
|
<path id="LM_level4-2" data-name="LM level4-2" d="M64.91,70.7,51.5,83.63,32.93,83,32.76,24c0-.84.16-.84.46-1.13l10.42-10.1.21-.19c.59-.4,2,.11,2,.95L65.29,34.25V70C65.3,70.44,65.16,70.43,64.91,70.7Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<image width="25" height="27" transform="translate(32 69)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAYAAAB/E6/TAAAACXBIWXMAAAsSAAALEgHS3X78AAABYUlEQVRIS+2WvVXDMBRG7/NxGVf0CRVFchghWSAVA2QAxmEGGgZgguzgHlPTELv/KCSD/BMs2wkV9xwf2/LPlZ70JJkk2piZdQojUd8PAWuXm1kGrIBF3wcDVEAhqWw/aIi8ZAcccLKxFMAzcGzL0voikDwCWyBjPGt8JMysKfMtMuAeeAE+Ac04TsArsAcySUj6blGGq82aaS0JyXARqYDCzHJJSnzItrh+ucW1bi4ZsCQYUAmu0w9M75dzNCqc4KxLLivpkPjzJcL1Kwl/xL9oMnXC1lkdw6SBk+IyOPf3Qz9Z8DOzD73bIAXegCfiloUV8ABs/HV07qWSKjPLiSP3xwY3m+yIlKVwflXsofSVeseFHCJlKSPxlTqZ2TEoHpSNFtVIKsfIJotgnGyWCHplW3pG8GwRdGQVbqXu35zMJZAVONEdgayzr5uL33wugBvgQ1IFVxDVmJmF+Xk1UZsvIeCPQjWq5BoAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
|
<path id="LM_level3-2" data-name="LM level3-2" d="M54,92V74.7a2.19,2.19,0,0,0-.3-1.12c-.28-.27-3.52-3.62-3.52-3.62a1.55,1.55,0,0,0-1.16-.4c-.75,0-11.62,0-11.62,0L33,74.26v8l10.66.57Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
</g>
|
||||||
|
<g id="LM_leftside" data-name="LM leftside">
|
||||||
|
<path id="LM_leftside5" data-name="LM leftside5" d="M60.08,126.64H54.47A5.45,5.45,0,0,1,49,121.18h0V98.28a5.46,5.46,0,0,1,5.46-5.46h5.61a5.47,5.47,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,60.08,126.64Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
<circle id="LM_leftside4" data-name="LM leftside4" cx="61.67" cy="123.24" r="3.79" style="fill: #fff"/>
|
||||||
|
<circle id="LM_leftside3" data-name="LM leftside3" cx="61.67" cy="100.03" r="3.79" style="fill: #fff"/>
|
||||||
|
<path id="LM_leftside2" data-name="LM leftside2" d="M57.77,116.72a4.15,4.15,0,0,1,2.34-.7,5.14,5.14,0,0,1,3,.7c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.84-1.23-.46l-1,.58s-.36.19-.36-.33V112s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.38-.29-1.33-.29-1.33H62.47s-.73,0-.73-.64v-1.3s-.23-.36-1.17-.31a3.57,3.57,0,0,0-1.4.31v1.3a.66.66,0,0,1-.66.64H57.25s-.25.2-.29,1.33.29,1.38.29,1.38h1.26s.8,0,.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.4-.82.46,0,1.8,0,1.8S57,117.16,57.77,116.72Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
|
<path id="LM_leftside1" data-name="LM leftside1" d="M64.62,104.92a.83.83,0,0,1-1,.68.68.68,0,0,1-.24-.08,6.46,6.46,0,0,0-2.85-.77,5,5,0,0,0-2.77.77c-.83.4-1.07-.6-1.07-.6v-1.76a.71.71,0,0,1,.76-.65.8.8,0,0,1,.31.09,5.79,5.79,0,0,0,2.77.84,7,7,0,0,0,2.85-.84s1.18-.24,1.2.56S64.62,104.92,64.62,104.92Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<image width="58" height="64" transform="translate(0 81)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAABBCAYAAABvnNwUAAAACXBIWXMAAAsSAAALEgHS3X78AAACFElEQVRoQ+2bQY7TMBSGvxcqsaFbJDbDrEEcYeYCcwYOwIlYsWLDjg0nGG6A1ANkbgCNhGb1WNgBpxPbaUjT+smf5E3lxPlq/25S5YmqshQiIrk+S6EzLlxmHDOKiGyB18CLXN8F6IAW6I6RXkTWi94C73HCp6YFvgI7oFXVfaY/sIBsIPoBuAG26SMWoZ/ZHfAZuJ8ivMl1SHEgess6ouDGeQtc4WMjInlhVZ3VcAPeAd+AX4Ceqf0EvgDv8Cs11hpm4Hfda1xG11q6MbbAG9+S1zFLliMGWIHBF++jNcrRmfUnu8Gd/Bo32Lnp9w4gnt+jZM+4IU0hKzxZ9sJyGiMpPFmWy8ppiqjwJNkLzWmK/no7oBWRnapqdje+8Jym2BLcdEDmp6eQnKYYrMDczJaS00lEZQvMaZZR2YJzmuSJrIGcRhmbWVM5DRnIWsxpyF9ZqzkNacB2TkP6mTWb05DGek5DGtxfn6aXb0+Du1G+wrgo/Mus2aUbknsQMEWVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUovq8le5TLwanBvbj4A2VKRwtjjvLr+g2fAb1wFxUvgFfB89NCy2APfgU/AD1V9BNio6l5E7oOOpb9u0It+5KC4aQNwINyxTonZqWiJVHENytNk3eLBU9ERqc97UovnXwArGj2U8vx34WFJ/AG0vvY6LSeZMAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
|
<path id="LM_level2_grey-2" data-name="LM level2 grey-2" d="M49,140.61H6.31a5.78,5.78,0,0,1-5.78-5.78h0V105.19C10.89,91.13,18.65,81.32,18.65,81.32h.6s19.46.15,23.86.15a2.29,2.29,0,0,1,2.38,1L54.75,92v42.8A5.78,5.78,0,0,1,49,140.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
</g>
|
||||||
|
<g id="LM_total" data-name="LM total">
|
||||||
|
<g id="LM_whitepart" data-name="LM whitepart">
|
||||||
|
<g style="clip-path: url(#clip-path-2)">
|
||||||
|
<g id="LM_whitepart_combined" data-name="LM whitepart combined">
|
||||||
|
<path id="LM_whitepart_top" data-name="LM whitepart top" d="M43.48,141l-7.15-7.37L12.54,102.56V87.7L-.52,103.84v31.22l1,7.69Z" transform="translate(0.98 1.9)" style="fill: #f1f1f1"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
|
<g>
|
||||||
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
|
<image width="47" height="52" transform="translate(5 87)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAA1CAYAAAAHz2g0AAAACXBIWXMAAAsSAAALEgHS3X78AAABnElEQVRoQ+2azXHCMBBG3zIccQuBM5MWoIHUkAJSUQrIJQWkAlIJ6SDYd+UgGWTjHxQHr5TRm9HFIzz75G8Z8KwYY5iKiMjYnr/AdBQrUwVEpADWwGps70Qq4GiMKf2LkwRc8XvgGStxT47AG3DwJZb9+4fxin8BdkAx/InJbHFPWUQuEsaY4IUt9gn4AE6AmWl9A+/AIy49CwJxDbvBxmaOk/cpgAe8fgsWwN5k69acxdc0vvGCBFzud9jT39C6mQY3C7Sado/O6V9xk4By7ge5SQD93PcyKhBj7n0GBWLNvU+vQArFQ49AzE3bpu8JRNu0ba4EYm/aNg2BVHLvcxZIKfc+/hNIJvc+C0gv9z4LF501iUWnpo7QCvtHIaniodkDycTGZ/THXOxkAW2ygDZZQJssoE0W0CYLaJMFtMkC2mQBbbKANv9K4PdDE/PSqLMWqIAvoDEJEiElts7qfEV59iFknbD1PQFFPbexBDDGlCJy4EJs70hL4BN4pW/cpiVRcf/5nxA6Z4WgY+BpxgmsEDqntWDixFYM/ACNRtJx4q2GRAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
|
<path id="LM_top_grey-2" data-name="LM top grey-2" d="M43.18,135.54H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.51C15,96.24,21.86,87.1,21.86,87.1H43.18A5.78,5.78,0,0,1,49,92.88h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
|
</g>
|
||||||
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
|
<g id="LM_top" data-name="LM top">
|
||||||
|
<g style="clip-path: url(#clip-path-3)">
|
||||||
|
<g id="LM_top_total" data-name="LM top total">
|
||||||
|
<path id="LM_top_lines" data-name="LM top lines" d="M18.6,112.05v27.47a1.08,1.08,0,0,1-1.12,1,1.06,1.06,0,0,1-1.05-1V112.05A1.09,1.09,0,0,1,18.6,112Zm3.61,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.62,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.61,0v27.47a1.09,1.09,0,0,1-2.17.07V112.05a1.09,1.09,0,0,1,2.17-.07Zm3.62,0v27.47A1.1,1.1,0,0,1,32,140.64a1.08,1.08,0,0,1-1.11-1V112.05a1.09,1.09,0,0,1,2.17-.07Z" transform="translate(0.98 1.9)" style="fill: #6a6a6a"/>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
</g>
|
||||||
|
<circle id="LM_detail_2" data-name="LM detail 2" cx="50.32" cy="137.11" r="2.24" style="fill: #9a9a9a"/>
|
||||||
|
<circle id="LM_detail_1" data-name="LM detail 1" cx="21.66" cy="86.59" r="2.24" style="fill: #9a9a9a"/>
|
||||||
|
<g id="hole">
|
||||||
<g>
|
<g>
|
||||||
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/>
|
<image width="38" height="38" transform="translate(44)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAYAAACMo1E1AAAACXBIWXMAAAsSAAALEgHS3X78AAACRklEQVRYR9WYPXLbMBBGHzgpxRwhTJ3ER0gukMauUvl0btIlhU9gdSkzQ9dWbmBTtTYFdiUA/BGh0ILyzWBAUiTx+C0JYdeJCDlyzrlgdwU02pu2wEb7vSR3IMDNvUahUpgGuNHetAF+aG/aA+dAzoJzztV4gI/EMHOdM+AW2IhIxwxNwqlbNfAZuMXDpTBhmE3pTQ24Be6ANdAdc/HN2A+JW7d4wJphmFTpOTX+Pu/wD7YCWufcpIuDzinYF2K36t6Jp6kjdvFhFFBEooaH+ArcA8/ADh+mJdtO732vY9Uph4iQgjngCviuFx8b5F/bs451hUYxbBWxauCDtqXCOKXp8UbC+cLxp16qvTAS3lLhTJuF9xNBeC2sK84bzlQ2bYXzJ5VOtA1+5n/PvHnsNdT7twmdswmyhEKDGltchF9rKcdMPYMMrjSYyRGwVJQPaaiIpSJek5V0MHrv4D9w7pK0Bf5oT5UeKCghWeJXyQEZvfQ8uljnTHuD7J0r7Zgp4gg/iNKAvQgaXOnQRh+DZWWVbtgPT5RzsJfvhs49apuV8C4sy8jiyF38Mj0AfAt8A37zOinhbLCh7KvjfOHd4d/xO2AtA4l1BKcfx/4CDuFdWh0+4/+l/aARvVqJiHTOuQfd3bJsOULwIGu8AS3wZFNHqtEq00QhB/LXfcIJlabRKpM62HKYnLccsiPrQxlwOlgIlVWjyy0eGlhazbTjcKRwSEZ1cxYcRLXgIeca4Fq3f7JAyRUy4EIlRWuYdo5cKNNJcOfSX2jmA7RYwAeRAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/>
|
<circle id="LM_red-2" data-name="LM red-2" cx="62.96" cy="18.95" r="17.06" style="fill: #d42715"/>
|
||||||
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/>
|
</g>
|
||||||
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/>
|
<g id="LM_details_in_red" data-name="LM details in red">
|
||||||
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/>
|
<circle id="LM_detail_red_hole4" data-name="LM detail red hole4" cx="59.9" cy="30.01" r="3.79" style="fill: #393939"/>
|
||||||
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/>
|
<circle id="LM_detail_red_hole3" data-name="LM detail red hole3" cx="51.75" cy="15.89" r="3.79" style="fill: #393939"/>
|
||||||
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/>
|
<circle id="LM_detail_red_hole2" data-name="LM detail red hole2" cx="65.87" cy="7.74" r="3.79" style="fill: #393939"/>
|
||||||
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/>
|
<circle id="LM_detail_red_hole1" data-name="LM detail red hole1" cx="74.02" cy="21.86" r="3.79" style="fill: #393939"/>
|
||||||
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/>
|
<path id="LM_detail_hole" data-name="LM detail hole" d="M64.2,16.41a.72.72,0,0,1-.55-.91c.21-.72.36-1.33.36-1.33s-.17-.35-1.27-.64-1.35-.06-1.35-.06L61,14.8s-.16.72-.81.54L59,15s-.4.13-.6,1.06a3.44,3.44,0,0,0-.06,1.43l1.25.33a.68.68,0,0,1,.46.81c-.16.61-.33,1.21-.33,1.21s.12.3,1.2.62,1.42.09,1.42.09l.32-1.22s.26-.76,1-.59q.6.17,1.2.39a2.92,2.92,0,0,0,.7-2.25C64.91,16.65,64.2,16.41,64.2,16.41Z" transform="translate(0.98 1.9)" style="fill: #1f1f1f"/>
|
||||||
|
<path id="LM_detail_red4" data-name="LM detail red4" d="M61.64,24.23,60.09,24l-1.53-.57a.46.46,0,0,1-.33-.56h0l.55-2.05a.46.46,0,0,1,.56-.32l1.45.6,1.63.22a.46.46,0,0,1,.33.56h0l-.55,2.05a.44.44,0,0,1-.55.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
|
<path id="LM_detail_red3" data-name="LM detail red3" d="M69.15,17.3l-.26,1.55-.57,1.52a.45.45,0,0,1-.55.33h0l-2.06-.55a.46.46,0,0,1-.32-.56L66,18.15l.22-1.63a.45.45,0,0,1,.55-.33h0l2,.55a.46.46,0,0,1,.32.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
|
<path id="LM_detail_red2" data-name="LM detail red2" d="M62.21,9.79l1.55.25,1.53.57a.46.46,0,0,1,.33.55h0l-.55,2.05a.46.46,0,0,1-.56.32l-1.45-.6-1.63-.22a.47.47,0,0,1-.33-.56h0l.55-2.05a.44.44,0,0,1,.55-.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
|
<path id="LM_detail_red1" data-name="LM detail red1" d="M54.7,16.72,55,15.17l.57-1.52a.45.45,0,0,1,.55-.33h0l2.06.55a.46.46,0,0,1,.32.56l-.61,1.44-.22,1.63a.45.45,0,0,1-.55.33h0l-2-.55a.46.46,0,0,1-.32-.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 15 KiB |
@ -1,70 +1,88 @@
|
|||||||
namespace pxsim {
|
namespace pxsim {
|
||||||
export const LARGE_MOTOR_SVG = `<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61">
|
export const LARGE_MOTOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 82 156">
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872">
|
<clipPath id="clip-path" transform="translate(0.98 1.9)">
|
||||||
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/>
|
<path d="M79,17.05A17.07,17.07,0,0,1,64.92,33.86l.36.39V70c0,.42-.14.4-.39.68L54,81.22v10l.75.78v.79h6.79a4,4,0,0,1,4,4v25.82a4,4,0,0,1-4,4H54.75v8.18A5.79,5.79,0,0,1,49,140.61h-6.5v7.57a4,4,0,0,1-2.9,3.84v1a.6.6,0,0,1-.6.6H12.69a.6.6,0,0,1-.6-.6h0v-1.29a4,4,0,0,1-2.17-3.55v-7.57H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59l13.68.1,0-11.8H26a4,4,0,0,1-4-4V39.79a4,4,0,0,1,4-4h6.78l0-11.77c0-.84.15-.84.46-1.14l10.41-10.1.22-.19a1.53,1.53,0,0,1,1.59.23A17.07,17.07,0,0,1,79,17.05Z" style="fill: none"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e">
|
<clipPath id="clip-path-2" transform="translate(0.98 1.9)">
|
||||||
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
<path d="M49,140.61H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59s19.46.14,23.87.14a2.27,2.27,0,0,1,2.37,1L54.75,92v42.79A5.79,5.79,0,0,1,49,140.61Z" style="fill: none"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927">
|
<clipPath id="clip-path-3" transform="translate(0.98 1.9)">
|
||||||
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/>
|
<path d="M43.18,135.24H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.21C15,95.94,21.86,86.8,21.86,86.8H43.18A5.78,5.78,0,0,1,49,92.58h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</defs>
|
</defs>
|
||||||
<title>Large Motor</title>
|
<title>Large Motor</title>
|
||||||
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)">
|
<g style="isolation: isolate">
|
||||||
<g>
|
<g id="e13b39e7-895d-4931-9be9-7aecaf709784">
|
||||||
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/>
|
<g style="clip-path: url(#clip-path)">
|
||||||
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/>
|
<g id="Large_Motor" data-name="Large Motor">
|
||||||
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
|
<path id="LM_back2" data-name="LM back2" d="M39,153.62H12.69a.6.6,0,0,1-.6-.6h0v-5.3a.6.6,0,0,1,.6-.6H39a.6.6,0,0,1,.6.6V153A.6.6,0,0,1,39,153.62Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
|
<g>
|
||||||
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
|
<image width="36" height="20" transform="translate(9 136)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAVCAYAAADB5CeuAAAACXBIWXMAAAsSAAALEgHS3X78AAAAp0lEQVRIS+3WsW3DMBBG4Y+GSmcGp/cAHsuzeIasFPdWVpD6c0FKcBWwOxV8wIEgSIAPvOL+EhFKKcUBiIiAgjO+25rJildErJMqdMdVlcwg8MQDv5P6Q1fc5ErRujW1TfmoLPa3T//dymJI9TKkehlSvQypXoZUL5vUNhAz2R1Oao75w9IOMmpRHVZqSpjxo3KRw+YwQ2lx+EsVykqfK+aIWGhSR+MNDy9ID5XUCOsAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
|
<path id="LM_back1-2" data-name="LM back1-2" d="M41.86,152.17H10.53a.6.6,0,0,1-.6-.6v-14.7a.6.6,0,0,1,.6-.6H41.86a.6.6,0,0,1,.6.6h0v14.7A.6.6,0,0,1,41.86,152.17Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
|
|
||||||
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
|
|
||||||
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
|
|
||||||
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
|
|
||||||
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
|
|
||||||
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
|
|
||||||
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
|
|
||||||
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
|
|
||||||
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
|
|
||||||
</g>
|
|
||||||
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/>
|
|
||||||
<g>
|
|
||||||
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03">
|
|
||||||
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)">
|
|
||||||
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153">
|
|
||||||
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
</g>
|
||||||
</g>
|
<g id="LM_rightside" data-name="LM rightside">
|
||||||
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
|
<path id="LM_rightside5" data-name="LM rightside5" d="M33.08,69.61H27.47A5.45,5.45,0,0,1,22,64.15h0V41.25a5.45,5.45,0,0,1,5.46-5.46h5.61a5.46,5.46,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,33.08,69.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
|
<circle id="LM_rightside4" data-name="LM rightside4" cx="28.3" cy="66.21" r="3.79" style="fill: #fff"/>
|
||||||
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
|
<circle id="LM_rightside3" data-name="LM rightside3" cx="28.3" cy="43" r="3.79" style="fill: #fff"/>
|
||||||
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
|
<path id="LM_rightside2" data-name="LM rightside2" d="M24.4,59.69A4.16,4.16,0,0,1,26.74,59a5.23,5.23,0,0,1,3,.71c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.85-1.23-.46l-1,.58s-.36.19-.36-.33V55s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.39-.29-1.32-.29-1.32H29.1s-.73,0-.73-.65v-1.3s-.23-.36-1.17-.3a3.56,3.56,0,0,0-1.4.3v1.3a.66.66,0,0,1-.66.65c-.63,0-1.26,0-1.26,0s-.25.19-.29,1.32.29,1.39.29,1.39h1.26s.8.05.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.41-.82.46,0,1.8,0,1.8S23.67,60.12,24.4,59.69Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
|
<path id="LM_rightside1" data-name="LM rightside1" d="M31.25,47.89a.84.84,0,0,1-1,.68.85.85,0,0,1-.24-.09,6.63,6.63,0,0,0-2.85-.77,5.11,5.11,0,0,0-2.77.77c-.83.4-1.07-.59-1.07-.59V46.13a.72.72,0,0,1,.76-.66.67.67,0,0,1,.31.1,5.79,5.79,0,0,0,2.77.84,7.12,7.12,0,0,0,2.85-.84s1.18-.24,1.2.56S31.25,47.89,31.25,47.89Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
|
</g>
|
||||||
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
|
<g>
|
||||||
|
<image width="36" height="76" transform="translate(32 12)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAABNCAYAAAAhOa00AAAACXBIWXMAAAsSAAALEgHS3X78AAACAElEQVRoQ+3avVHDMBiA4VdcypgREmo4RggLpKKHAZiIAWgoKZggrEAGCBsQpxeFpNgJ/vkkK5YLvXe6g2Cb53zE9oVPaa3xSSmlALTvjh4pn2MrpQpgab/dAYdL4MQoC3oAnuxLH8AW2Gmty9YdAxKhaqAXYAUozJnaAm/AJiZs1rfBGegBKOyP7oAFMLfbRYN1ojpAYM7WtX3dbR8F1orqAdVz27n9BsMaUR4gV1yY1vpkYX7BGvgE9oD2WL/AO3CPfROFrKs6MOAMnVcAt3b57lsV6QzV194eYw0UfWelacUGRYFdAjQYNsPcy54xV+rwv4P/Bb8jZ5gr8oK4IFcQzF2nVOdWw/KG9d77IuUFGwsFHrAxUSCEjY0CASwFCnpgqVDQAUuJghZYahQY2Ao4YJ77v08eXRJWUHvenwoKaneVKaGOZZS0jJKWUdIySlpGScsoaRklLaOkZZS0jJKWUdIySlpGScsoaRklLaOkTQml3RdTQZXAD+bD2EmgSuALMwmyg/SoEtgAr9RGU1KiGkGQDtUKgjSoThCMj+oFwbgoEQjGQ4lBMA7KCwSXR3mDoPonpBsFccWYUwgCgUEdMAN/YDBzzKjJvG0nQe7W4Q2CCnFDhVgCj1TznCHtGDDVqLTWxylXW4wzdWDA/GfjnOcZMijddGBhouHTsfsDst/cEY24RzwAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
|
<path id="LM_level4-2" data-name="LM level4-2" d="M64.91,70.7,51.5,83.63,32.93,83,32.76,24c0-.84.16-.84.46-1.13l10.42-10.1.21-.19c.59-.4,2,.11,2,.95L65.29,34.25V70C65.3,70.44,65.16,70.43,64.91,70.7Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<image width="25" height="27" transform="translate(32 69)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAYAAAB/E6/TAAAACXBIWXMAAAsSAAALEgHS3X78AAABYUlEQVRIS+2WvVXDMBRG7/NxGVf0CRVFchghWSAVA2QAxmEGGgZgguzgHlPTELv/KCSD/BMs2wkV9xwf2/LPlZ70JJkk2piZdQojUd8PAWuXm1kGrIBF3wcDVEAhqWw/aIi8ZAcccLKxFMAzcGzL0voikDwCWyBjPGt8JMysKfMtMuAeeAE+Ac04TsArsAcySUj6blGGq82aaS0JyXARqYDCzHJJSnzItrh+ucW1bi4ZsCQYUAmu0w9M75dzNCqc4KxLLivpkPjzJcL1Kwl/xL9oMnXC1lkdw6SBk+IyOPf3Qz9Z8DOzD73bIAXegCfiloUV8ABs/HV07qWSKjPLiSP3xwY3m+yIlKVwflXsofSVeseFHCJlKSPxlTqZ2TEoHpSNFtVIKsfIJotgnGyWCHplW3pG8GwRdGQVbqXu35zMJZAVONEdgayzr5uL33wugBvgQ1IFVxDVmJmF+Xk1UZsvIeCPQjWq5BoAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
|
<path id="LM_level3-2" data-name="LM level3-2" d="M54,92V74.7a2.19,2.19,0,0,0-.3-1.12c-.28-.27-3.52-3.62-3.52-3.62a1.55,1.55,0,0,0-1.16-.4c-.75,0-11.62,0-11.62,0L33,74.26v8l10.66.57Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
</g>
|
||||||
|
<g id="LM_leftside" data-name="LM leftside">
|
||||||
|
<path id="LM_leftside5" data-name="LM leftside5" d="M60.08,126.64H54.47A5.45,5.45,0,0,1,49,121.18h0V98.28a5.46,5.46,0,0,1,5.46-5.46h5.61a5.47,5.47,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,60.08,126.64Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
<circle id="LM_leftside4" data-name="LM leftside4" cx="61.67" cy="123.24" r="3.79" style="fill: #fff"/>
|
||||||
|
<circle id="LM_leftside3" data-name="LM leftside3" cx="61.67" cy="100.03" r="3.79" style="fill: #fff"/>
|
||||||
|
<path id="LM_leftside2" data-name="LM leftside2" d="M57.77,116.72a4.15,4.15,0,0,1,2.34-.7,5.14,5.14,0,0,1,3,.7c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.84-1.23-.46l-1,.58s-.36.19-.36-.33V112s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.38-.29-1.33-.29-1.33H62.47s-.73,0-.73-.64v-1.3s-.23-.36-1.17-.31a3.57,3.57,0,0,0-1.4.31v1.3a.66.66,0,0,1-.66.64H57.25s-.25.2-.29,1.33.29,1.38.29,1.38h1.26s.8,0,.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.4-.82.46,0,1.8,0,1.8S57,117.16,57.77,116.72Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
|
<path id="LM_leftside1" data-name="LM leftside1" d="M64.62,104.92a.83.83,0,0,1-1,.68.68.68,0,0,1-.24-.08,6.46,6.46,0,0,0-2.85-.77,5,5,0,0,0-2.77.77c-.83.4-1.07-.6-1.07-.6v-1.76a.71.71,0,0,1,.76-.65.8.8,0,0,1,.31.09,5.79,5.79,0,0,0,2.77.84,7,7,0,0,0,2.85-.84s1.18-.24,1.2.56S64.62,104.92,64.62,104.92Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<image width="58" height="64" transform="translate(0 81)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAABBCAYAAABvnNwUAAAACXBIWXMAAAsSAAALEgHS3X78AAACFElEQVRoQ+2bQY7TMBSGvxcqsaFbJDbDrEEcYeYCcwYOwIlYsWLDjg0nGG6A1ANkbgCNhGb1WNgBpxPbaUjT+smf5E3lxPlq/25S5YmqshQiIrk+S6EzLlxmHDOKiGyB18CLXN8F6IAW6I6RXkTWi94C73HCp6YFvgI7oFXVfaY/sIBsIPoBuAG26SMWoZ/ZHfAZuJ8ivMl1SHEgess6ouDGeQtc4WMjInlhVZ3VcAPeAd+AX4Ceqf0EvgDv8Cs11hpm4Hfda1xG11q6MbbAG9+S1zFLliMGWIHBF++jNcrRmfUnu8Gd/Bo32Lnp9w4gnt+jZM+4IU0hKzxZ9sJyGiMpPFmWy8ppiqjwJNkLzWmK/no7oBWRnapqdje+8Jym2BLcdEDmp6eQnKYYrMDczJaS00lEZQvMaZZR2YJzmuSJrIGcRhmbWVM5DRnIWsxpyF9ZqzkNacB2TkP6mTWb05DGek5DGtxfn6aXb0+Du1G+wrgo/Mus2aUbknsQMEWVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUovq8le5TLwanBvbj4A2VKRwtjjvLr+g2fAb1wFxUvgFfB89NCy2APfgU/AD1V9BNio6l5E7oOOpb9u0It+5KC4aQNwINyxTonZqWiJVHENytNk3eLBU9ERqc97UovnXwArGj2U8vx34WFJ/AG0vvY6LSeZMAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
|
<path id="LM_level2_grey-2" data-name="LM level2 grey-2" d="M49,140.61H6.31a5.78,5.78,0,0,1-5.78-5.78h0V105.19C10.89,91.13,18.65,81.32,18.65,81.32h.6s19.46.15,23.86.15a2.29,2.29,0,0,1,2.38,1L54.75,92v42.8A5.78,5.78,0,0,1,49,140.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
|
</g>
|
||||||
|
<g id="LM_total" data-name="LM total">
|
||||||
|
<g id="LM_whitepart" data-name="LM whitepart">
|
||||||
|
<g style="clip-path: url(#clip-path-2)">
|
||||||
|
<g id="LM_whitepart_combined" data-name="LM whitepart combined">
|
||||||
|
<path id="LM_whitepart_top" data-name="LM whitepart top" d="M43.48,141l-7.15-7.37L12.54,102.56V87.7L-.52,103.84v31.22l1,7.69Z" transform="translate(0.98 1.9)" style="fill: #f1f1f1"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
|
<g>
|
||||||
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
|
<image width="47" height="52" transform="translate(5 87)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAA1CAYAAAAHz2g0AAAACXBIWXMAAAsSAAALEgHS3X78AAABnElEQVRoQ+2azXHCMBBG3zIccQuBM5MWoIHUkAJSUQrIJQWkAlIJ6SDYd+UgGWTjHxQHr5TRm9HFIzz75G8Z8KwYY5iKiMjYnr/AdBQrUwVEpADWwGps70Qq4GiMKf2LkwRc8XvgGStxT47AG3DwJZb9+4fxin8BdkAx/InJbHFPWUQuEsaY4IUt9gn4AE6AmWl9A+/AIy49CwJxDbvBxmaOk/cpgAe8fgsWwN5k69acxdc0vvGCBFzud9jT39C6mQY3C7Sado/O6V9xk4By7ge5SQD93PcyKhBj7n0GBWLNvU+vQArFQ49AzE3bpu8JRNu0ba4EYm/aNg2BVHLvcxZIKfc+/hNIJvc+C0gv9z4LF501iUWnpo7QCvtHIaniodkDycTGZ/THXOxkAW2ygDZZQJssoE0W0CYLaJMFtMkC2mQBbbKANv9K4PdDE/PSqLMWqIAvoDEJEiElts7qfEV59iFknbD1PQFFPbexBDDGlCJy4EJs70hL4BN4pW/cpiVRcf/5nxA6Z4WgY+BpxgmsEDqntWDixFYM/ACNRtJx4q2GRAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
|
<path id="LM_top_grey-2" data-name="LM top grey-2" d="M43.18,135.54H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.51C15,96.24,21.86,87.1,21.86,87.1H43.18A5.78,5.78,0,0,1,49,92.88h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
|
||||||
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
|
</g>
|
||||||
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
|
<g id="LM_top" data-name="LM top">
|
||||||
|
<g style="clip-path: url(#clip-path-3)">
|
||||||
|
<g id="LM_top_total" data-name="LM top total">
|
||||||
|
<path id="LM_top_lines" data-name="LM top lines" d="M18.6,112.05v27.47a1.08,1.08,0,0,1-1.12,1,1.06,1.06,0,0,1-1.05-1V112.05A1.09,1.09,0,0,1,18.6,112Zm3.61,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.62,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.61,0v27.47a1.09,1.09,0,0,1-2.17.07V112.05a1.09,1.09,0,0,1,2.17-.07Zm3.62,0v27.47A1.1,1.1,0,0,1,32,140.64a1.08,1.08,0,0,1-1.11-1V112.05a1.09,1.09,0,0,1,2.17-.07Z" transform="translate(0.98 1.9)" style="fill: #6a6a6a"/>
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
</g>
|
||||||
|
<circle id="LM_detail_2" data-name="LM detail 2" cx="50.32" cy="137.11" r="2.24" style="fill: #9a9a9a"/>
|
||||||
|
<circle id="LM_detail_1" data-name="LM detail 1" cx="21.66" cy="86.59" r="2.24" style="fill: #9a9a9a"/>
|
||||||
|
<g id="hole">
|
||||||
<g>
|
<g>
|
||||||
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/>
|
<image width="38" height="38" transform="translate(44)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAYAAACMo1E1AAAACXBIWXMAAAsSAAALEgHS3X78AAACRklEQVRYR9WYPXLbMBBGHzgpxRwhTJ3ER0gukMauUvl0btIlhU9gdSkzQ9dWbmBTtTYFdiUA/BGh0ILyzWBAUiTx+C0JYdeJCDlyzrlgdwU02pu2wEb7vSR3IMDNvUahUpgGuNHetAF+aG/aA+dAzoJzztV4gI/EMHOdM+AW2IhIxwxNwqlbNfAZuMXDpTBhmE3pTQ24Be6ANdAdc/HN2A+JW7d4wJphmFTpOTX+Pu/wD7YCWufcpIuDzinYF2K36t6Jp6kjdvFhFFBEooaH+ArcA8/ADh+mJdtO732vY9Uph4iQgjngCviuFx8b5F/bs451hUYxbBWxauCDtqXCOKXp8UbC+cLxp16qvTAS3lLhTJuF9xNBeC2sK84bzlQ2bYXzJ5VOtA1+5n/PvHnsNdT7twmdswmyhEKDGltchF9rKcdMPYMMrjSYyRGwVJQPaaiIpSJek5V0MHrv4D9w7pK0Bf5oT5UeKCghWeJXyQEZvfQ8uljnTHuD7J0r7Zgp4gg/iNKAvQgaXOnQRh+DZWWVbtgPT5RzsJfvhs49apuV8C4sy8jiyF38Mj0AfAt8A37zOinhbLCh7KvjfOHd4d/xO2AtA4l1BKcfx/4CDuFdWh0+4/+l/aARvVqJiHTOuQfd3bJsOULwIGu8AS3wZFNHqtEq00QhB/LXfcIJlabRKpM62HKYnLccsiPrQxlwOlgIlVWjyy0eGlhazbTjcKRwSEZ1cxYcRLXgIeca4Fq3f7JAyRUy4EIlRWuYdo5cKNNJcOfSX2jmA7RYwAeRAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||||
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/>
|
<circle id="LM_red-2" data-name="LM red-2" cx="62.96" cy="18.95" r="17.06" style="fill: #d42715"/>
|
||||||
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/>
|
</g>
|
||||||
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/>
|
<g id="LM_details_in_red" data-name="LM details in red">
|
||||||
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/>
|
<circle id="LM_detail_red_hole4" data-name="LM detail red hole4" cx="59.9" cy="30.01" r="3.79" style="fill: #393939"/>
|
||||||
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/>
|
<circle id="LM_detail_red_hole3" data-name="LM detail red hole3" cx="51.75" cy="15.89" r="3.79" style="fill: #393939"/>
|
||||||
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/>
|
<circle id="LM_detail_red_hole2" data-name="LM detail red hole2" cx="65.87" cy="7.74" r="3.79" style="fill: #393939"/>
|
||||||
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/>
|
<circle id="LM_detail_red_hole1" data-name="LM detail red hole1" cx="74.02" cy="21.86" r="3.79" style="fill: #393939"/>
|
||||||
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/>
|
<path id="LM_detail_hole" data-name="LM detail hole" d="M64.2,16.41a.72.72,0,0,1-.55-.91c.21-.72.36-1.33.36-1.33s-.17-.35-1.27-.64-1.35-.06-1.35-.06L61,14.8s-.16.72-.81.54L59,15s-.4.13-.6,1.06a3.44,3.44,0,0,0-.06,1.43l1.25.33a.68.68,0,0,1,.46.81c-.16.61-.33,1.21-.33,1.21s.12.3,1.2.62,1.42.09,1.42.09l.32-1.22s.26-.76,1-.59q.6.17,1.2.39a2.92,2.92,0,0,0,.7-2.25C64.91,16.65,64.2,16.41,64.2,16.41Z" transform="translate(0.98 1.9)" style="fill: #1f1f1f"/>
|
||||||
|
<path id="LM_detail_red4" data-name="LM detail red4" d="M61.64,24.23,60.09,24l-1.53-.57a.46.46,0,0,1-.33-.56h0l.55-2.05a.46.46,0,0,1,.56-.32l1.45.6,1.63.22a.46.46,0,0,1,.33.56h0l-.55,2.05a.44.44,0,0,1-.55.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
|
<path id="LM_detail_red3" data-name="LM detail red3" d="M69.15,17.3l-.26,1.55-.57,1.52a.45.45,0,0,1-.55.33h0l-2.06-.55a.46.46,0,0,1-.32-.56L66,18.15l.22-1.63a.45.45,0,0,1,.55-.33h0l2,.55a.46.46,0,0,1,.32.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
|
<path id="LM_detail_red2" data-name="LM detail red2" d="M62.21,9.79l1.55.25,1.53.57a.46.46,0,0,1,.33.55h0l-.55,2.05a.46.46,0,0,1-.56.32l-1.45-.6-1.63-.22a.47.47,0,0,1-.33-.56h0l.55-2.05a.44.44,0,0,1,.55-.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
|
<path id="LM_detail_red1" data-name="LM detail red1" d="M54.7,16.72,55,15.17l.57-1.52a.45.45,0,0,1,.55-.33h0l2.06.55a.46.46,0,0,1,.32.56l-.61,1.44-.22,1.63a.45.45,0,0,1-.55.33h0l-2-.55a.46.46,0,0,1-.32-.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|