Compare commits

...

40 Commits

Author SHA1 Message Date
4e9d3aa413 0.0.10 2017-08-07 11:33:51 -07:00
1efad776e6 bump pxt-core to 2.0.6, 2017-08-07 11:33:46 -07:00
5e7af872b5 Add setLights shadow block 2017-08-07 10:19:38 -07:00
17683033b1 Add branch info 2017-08-07 12:15:56 +02:00
31f3d108c5 Update build instructions 2017-08-07 12:15:06 +02:00
b45bf7512c 0.0.9 2017-08-07 11:13:05 +02:00
2dec405a9b Catch errors from initAsync 2017-08-07 11:12:52 +02:00
29009aa5e5 0.0.8 2017-08-07 11:08:15 +02:00
86011827dc Fix initialization without HID 2017-08-07 10:56:21 +02:00
c20cfab069 Fix web deployment, only use HF2 when in localhost (#2) 2017-08-05 17:54:18 +01:00
197f9096f8 0.0.7 2017-08-04 22:53:11 -07:00
6d499cb683 Fix package.json 2017-08-04 22:52:53 -07:00
163a4f89f8 0.0.6 2017-08-04 22:41:39 -07:00
b32aa61cd1 Update package.json 2017-08-04 21:17:52 -07:00
db7cf212d4 0.0.5 2017-08-04 21:06:51 -07:00
c8fb59cdde bump pxt-common-packages to 0.9.2, 2017-08-04 21:06:46 -07:00
264156c485 0.0.4 2017-08-04 20:58:47 -07:00
440dbbe82a Update style, use freshcoat 2017-08-04 20:54:22 -07:00
f4660b4366 0.0.3 2017-08-04 15:25:45 -07:00
a4be9f07ea Add robots no index 2017-08-04 15:25:33 -07:00
0c8661808b 0.0.2 2017-08-04 15:16:21 -07:00
b234337dda Update styles 2017-08-04 15:14:24 -07:00
c9cdd3112a 0.0.1 2017-08-04 15:03:26 -07:00
fe7e3a8790 Update to latest pxt-core and pxt-common-packages with codalnext changes 2017-08-04 15:03:14 -07:00
8321c76f4c Use the correct size limit for CRAMFS (10M) 2017-07-27 21:11:23 +01:00
227f9614b0 Strip lego- prefix from files on the brick 2017-07-27 21:10:52 +01:00
de0b5f0d86 Allow writing to currently executing files 2017-07-27 20:42:28 +01:00
abdb21f2a0 Update readme 2017-07-27 14:36:01 +01:00
b16f659ea1 Start user app by invoking .rbf file (via added ioctl on usbdev) 2017-07-27 14:31:23 +01:00
34db42b469 Remove UF2 file repetition 2017-07-27 12:50:12 +01:00
3edceb248d Disable DMA in the MUSB driver 2017-07-27 12:49:34 +01:00
8f9b9a5e4e Use kernel log-level 6 by default 2017-07-27 12:49:19 +01:00
14783eadc2 Workaround UF2 driver problems by repeating the file 3 times 2017-07-26 19:14:12 +01:00
5e7754b436 More info about how images are created 2017-07-26 18:57:46 +01:00
c6b4e506d1 Send restart request to uf2d upon usb disconnect 2017-07-26 18:14:26 +01:00
52ef98e249 Add more logging 2017-07-26 10:43:43 +01:00
9a3eec7d4d dmesg logging 2017-07-25 19:09:32 +01:00
d2f6395443 Cleanup logging; remove excessive flush 2017-07-25 18:37:52 +01:00
7960c9f15e Logging fixes 2017-07-25 15:28:28 +01:00
d84b2b187c Remove unnecessary changes; trim down logging 2017-07-25 15:10:06 +01:00
27 changed files with 529 additions and 183 deletions

View File

@ -9,12 +9,12 @@ This repo contains the editor target hosted at https://lego.makecode.com
These instructions assume familiarity with dev tools and languages.
* install Node.js 6+
* install [yotta](http://docs.yottabuild.org/#installing)
* install Docker; make sure `docker` command is in your `PATH`
* (optional) install [Visual Studio Code](https://code.visualstudio.com/)
In a common folder,
* clone https://github.com/Microsoft/pxt to ``pxt`` folder
* clone https://github.com/Microsoft/pxt to ``pxt`` folder (currently, build against `freshcoat` branch)
* clone https://github.com/Microsoft/pxt-common-packages to ``pxt-common-packages`` folder
* clone https://github.com/Microsoft/pxt-ev3 to ``pxt-ev3`` folder
* go to ``pxt`` and run

View File

@ -11,8 +11,9 @@ they are derived from GPLv2 code).
* the `d_usbdev` uses the composite framework to register an additional mass storage function in addtion
to the pre-existing custom USB HID function
* the `g_mass_storage` module has the following changes:
* a bug fixed, where page-misaligned writes would hang
* additional `/sys/.../lun0/active` entry is added, which allows for signaling drive eject to the host
* `d_usbdev` has an additional `ioctl()` to pretend data came from the USB host - this can be used to direct
the VM to do stuff
### Kernel modifications

View File

@ -1,9 +1,10 @@
#!/bin/sh
set -ex
echo Y > /sys/module/printk/parameters/time
cd /mnt/ramdisk/prjs/ko
echo 3 > /proc/sys/kernel/printk
#echo 3 > /proc/sys/kernel/printk
insmod ./nbd.ko
sleep 1
./uf2d > /tmp/uf2d.log 2> /tmp/uf2derr.log
./uf2d /dev/nbd1 > /tmp/uf2d.log 2> /tmp/uf2derr.log
sleep 1
insmod ./d_usbdev.ko file=/dev/nbd0 HostStr=EV3 SerialStr=0016535543af
insmod ./d_usbdev.ko file=/dev/nbd1 HostStr=EV3 SerialStr=0016535543af

View File

@ -38,11 +38,12 @@
// Keep Eclipse happy
#endif
#if 1
#undef dev_vdbg
#undef dev_dbg
#define dev_vdbg(d, args...) printk(args)
#define dev_dbg(d, args...) printk(args)
#endif
/* big enough to hold our biggest descriptor */
#define USB_BUFSIZ 1024

View File

@ -80,9 +80,6 @@ static void ModuleExit(void);
#include <linux/utsname.h>
#include <linux/device.h>
void myReset(void);
static int dUsbInit(void);
static void dUsbExit(void);
static struct fsg_common *fsg_common;
#include "computil.c" // The composite framework used as utility file
@ -546,12 +543,27 @@ static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
return (ret);
}
#define FEED_DATA _IOC(_IOC_WRITE, 't', 108, 1024)
static int Device1Ioctl(struct inode *pNode, struct file *File, unsigned int Request, unsigned long Pointer)
{
if (Request != FEED_DATA)
return -EINVAL;
copy_from_user(usb_char_buffer_out,(void*)Pointer,1024);
usb_char_out_length = 1024;
return 0;
}
static const struct file_operations Device1Entries =
{
.owner = THIS_MODULE,
.read = Device1Read,
.write = Device1Write,
.mmap = Device1Mmap
.mmap = Device1Mmap,
.ioctl = Device1Ioctl
};
@ -748,8 +760,3 @@ static int msg_bind(struct usb_composite_dev *cdev)
static int msg_config(struct usb_configuration *c) {
return fsg_add(c->cdev, c, fsg_common);
}
void myReset() {
dUsbExit();
dUsbInit();
}

View File

@ -705,6 +705,8 @@ static int do_read(struct fsg_common *common)
u32 amount_left;
loff_t file_offset, file_offset_tmp;
unsigned int amount;
// partial_page handling causes hangs
// same thing in do_write() --mmoskal
//unsigned int partial_page;
ssize_t nread;
@ -731,6 +733,9 @@ static int do_read(struct fsg_common *common)
/* Carry out the file reads */
amount_left = common->data_size_from_cmnd;
LDBG(curlun, "Uread off=%d cnt=%d\n", (int)lba, amount_left);
if (unlikely(amount_left == 0))
return -EIO; /* No default reply */
@ -879,6 +884,8 @@ static int do_write(struct fsg_common *common)
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;
LDBG(curlun, "Uwrite off=%d cnt=%d\n", (int)lba, amount_left_to_req);
while (amount_left_to_write > 0) {
/* Queue a request for more data from the host */
@ -2403,7 +2410,28 @@ static void fsg_disable(struct usb_function *f)
fsg->common->prev_fsg = fsg->common->fsg;
fsg->common->fsg = fsg;
fsg->common->new_config = 0;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
DBG(common, "fsg_disable filp=%p\n", fsg->common->luns[0].filp);
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE_DISABLE);
}
static void shutdown_server(void) {
DBG(fsg_common, "shutdown_server filp=%p\n", fsg_common->luns[0].filp);
if (fsg_common->luns[0].filp) {
uint32_t buf[512 / 4];
loff_t file_offset_tmp = 512 * 50000; // make sure we're outside of FS area
int i;
// this should shut down the nbd server, so that the caches are flushed
memset(buf, 0, sizeof(buf));
buf[0] = 0x20da6d81;
buf[1] = 0x747e09d4;
fsg_common->luns[0].filp->f_flags |= O_SYNC;
for (i = 0; i < 2; ++i)
vfs_write(fsg_common->luns[0].filp,
(char*)buf, 512, &file_offset_tmp);
}
}
@ -2525,6 +2553,9 @@ static void handle_exception(struct fsg_common *common)
/* SS_RESET_OCCURRED; */
break;
case FSG_STATE_CONFIG_CHANGE_DISABLE:
shutdown_server();
// fall-through
case FSG_STATE_CONFIG_CHANGE:
rc = do_set_config(common, new_config);
if (common->ep0_req_tag != exception_req_tag)
@ -2651,19 +2682,6 @@ static ssize_t fsg_store_active(struct device *dev, struct device_attribute *att
if (sscanf(buf, "%d", &i) != 1)
return -EINVAL;
/*
if (i == 0) {
dUsbExit();
dUsbInit();
}
else if (i == 1) {
do_set_config(fsg_common, 0);
}
else if (i == 2) {
raise_exception(fsg_common, FSG_STATE_CONFIG_CHANGE);
}
*/
if (isActive() != i) {
if (i == 0) {

View File

@ -334,6 +334,7 @@ enum fsg_state {
FSG_STATE_ABORT_BULK_OUT,
FSG_STATE_RESET,
FSG_STATE_INTERFACE_CHANGE,
FSG_STATE_CONFIG_CHANGE_DISABLE,
FSG_STATE_CONFIG_CHANGE,
FSG_STATE_DISCONNECT,
FSG_STATE_EXIT,
@ -749,13 +750,11 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
struct rw_semaphore *filesem = dev_get_drvdata(dev);
int rc = 0;
#if 0
if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
LDBG(curlun, "eject attempt prevented\n");
return -EBUSY; /* "Door is locked" */
}
#endif
/* Remove a trailing newline */
if (count > 0 && buf[count-1] == '\n')

View File

@ -734,6 +734,5 @@ int rudolf_add(struct usb_composite_dev *cdev, bool autoresume)
rudolf_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
return usb_add_config(cdev, &rudolf_driver);
}

14
brick/scripts/README.md Normal file
View File

@ -0,0 +1,14 @@
# Patched EV3 image
The file `ev3-fs.patch` summarizes the changes done to the original V1.09D image.
You can see some text files are edited, the `d_usbdev.ko` is updated (sources in `../kernel`),
`uf2d` added (sources in `../uf2daemon`), and a stock `nbd.ko` module is added.
Additionally, the `edimax01.ko` is replaced by now much more popular `rtl8192cu.ko` (also stock).
The init script has a hook for running a shell script from `/mnt/ramdisk/`. This can be used
for testing different modules etc.
The kernel command line has been modified to:
* disable DMA for the MUSB driver - otherwise the mass storage device is very unstable
* increase the size of dmesg buffer to 128k

View File

@ -0,0 +1,53 @@
diff -ur orig-ev3/etc/init.d/ev3init.sh dev-ev3/etc/init.d/ev3init.sh
--- orig-ev3/etc/init.d/ev3init.sh 1970-01-01 01:00:00.000000000 +0100
+++ dev-ev3/etc/init.d/ev3init.sh 2017-07-27 12:19:43.195041798 +0100
@@ -1,5 +1,7 @@
#!/bin/sh
+echo Y > /sys/module/printk/parameters/time
+
bluetoothd -n > /dev/null 2>&1 &
echo "Setting up VirtualDrive...";
@@ -60,3 +62,6 @@
sleep 2
hciattach /dev/ttyS2 texas 2000000 "flow" "nosleep" $STRING
sdptool add SP
+
+insmod /lib/modules/2.6.33-rc4/kernel/drivers/net/wireless/rtl8192cu.ko
+. /mnt/ramdisk/rc.local || :
Only in orig-ev3/home/root/lms2012/sys: exit~
diff -ur orig-ev3/home/root/lms2012/sys/init dev-ev3/home/root/lms2012/sys/init
--- orig-ev3/home/root/lms2012/sys/init 1970-01-01 01:00:00.000000000 +0100
+++ dev-ev3/home/root/lms2012/sys/init 2017-07-27 12:23:43.072605126 +0100
@@ -5,13 +5,15 @@
var=$(printf 'HostStr=%s SerialStr=%s' $(cat /home/root/lms2012/sys/settings/BrickName) $(cat /home/root/lms2012/sys/settings/BTser))
echo $var > /home/root/lms2012/sys/settings/UsbInfo.dat
+insmod ${PWD}/mod/nbd.ko
+${PWD}/uf2d
insmod ${PWD}/mod/d_iic.ko `cat /home/root/lms2012/sys/settings/HwId`
insmod ${PWD}/mod/d_uart.ko `cat /home/root/lms2012/sys/settings/HwId`
insmod ${PWD}/mod/d_power.ko `cat /home/root/lms2012/sys/settings/HwId`
insmod ${PWD}/mod/d_pwm.ko `cat /home/root/lms2012/sys/settings/HwId`
insmod ${PWD}/mod/d_ui.ko `cat /home/root/lms2012/sys/settings/HwId`
insmod ${PWD}/mod/d_analog.ko `cat /home/root/lms2012/sys/settings/HwId`
-insmod ${PWD}/mod/d_usbdev.ko `cat /home/root/lms2012/sys/settings/UsbInfo.dat`
+insmod ${PWD}/mod/d_usbdev.ko `cat /home/root/lms2012/sys/settings/UsbInfo.dat` file=/dev/nbd0
insmod ${PWD}/mod/d_usbhost.ko
insmod ${PWD}/mod/d_sound.ko `cat /home/root/lms2012/sys/settings/HwId`
insmod ${PWD}/mod/d_bt.ko `cat /home/root/lms2012/sys/settings/HwId`
@@ -29,6 +31,8 @@
chmod 666 /dev/lms_iic
chmod 666 /dev/lms_bt
+echo 4 > /proc/sys/kernel/printk
+
cd ..
ls -R > /dev/null
cd sys
Binary files orig-ev3/home/root/lms2012/sys/mod/d_usbdev.ko and dev-ev3/home/root/lms2012/sys/mod/d_usbdev.ko differ
Only in dev-ev3/home/root/lms2012/sys/mod: nbd.ko
Only in dev-ev3/home/root/lms2012/sys: uf2d
Only in orig-ev3/lib/modules/2.6.33-rc4/kernel/drivers/net/wireless: edimax01.ko
Only in dev-ev3/lib/modules/2.6.33-rc4/kernel/drivers/net/wireless: rtl8192cu.ko

View File

@ -1,14 +1,36 @@
#!/bin/sh
let fs = require("fs")
// we try to use shorter versions of all parameters for the additional parameters to fit
let bootargs = "mem=${memsize} initrd=${filesysaddr},${filesyssize} root=/dev/ram0 rw rootfstype=cramfs console=${console} ip=${ipaddr} lpj=747520 quiet"
let bootnews = "mem=64M initrd=0xC1180000,10M root=1:0 rw rootfstype=cramfs console=${console} lpj=747520 musb_hdrc.use_dma=0 log_buf_len=128k quiet"
let piggy = true
function build() {
let cr = fs.readFileSync("cram.bin")
if (cr.length > 10878976) {
console.log("too big")
if (bootnews.length > bootargs.length) {
console.log("args too long")
return
}
let img = fs.readFileSync("boot.bin")
while (bootnews.length < bootargs.length)
bootnews += " "
let cr = fs.readFileSync("cram.bin")
if (cr.length > 10485760) {
console.log("too big by " + (cr.length - 10485760))
return
}
let img = fs.readFileSync("EV3 Firmware V1.09D.bin")
for (let i = 0; i < bootnews.length; ++i) {
if (img[0x21DDA + i] != bootargs.charCodeAt(i)) {
console.log("boot args mismatch")
return
}
img[0x21DDA + i] = bootnews.charCodeAt(i)
}
let off = 0x250000
if (img[off] != 0x45 || img[off + 1] != 0x3d) {
console.log("bad magic: " + img[off] + " / " + img[off+1])
@ -17,8 +39,8 @@ function build() {
cr.copy(img, off)
let kern = fs.readFileSync("piggy-patched.gzip")
off = 0x0005540f
let kern = fs.readFileSync(piggy ? "piggy-patched.gzip" : "linux/arch/arm/boot/uImage")
off = piggy ? 0x0005540f : 0x00050000
if (img[off] != kern[0] || img[off+1] != kern[1]) {
console.log("bad kernel magic: " + img[off] + " / " + img[off+1])

View File

@ -1,4 +1,9 @@
#!/bin/sh
# dd if=EV3\ Firmware\ V1.09D.bin of=orig.cram bs=65536 skip=37 count=400
sudo cp linux/pxt/uf2daemon/server dev-ev3/home/root/lms2012/sys/uf2d
sudo cp linux/pxt/kernel/d_usbdev.ko dev-ev3/home/root/lms2012/sys/mod/d_usbdev.ko
sudo chown -R root:root dev-ev3/home/root/lms2012
sudo mkfs.cramfs dev-ev3 cram.bin
node img
ls -l firmware.bin

View File

@ -6,4 +6,5 @@ ev3duder up bin/nbd.ko ../prjs/ko/nbd.ko
ev3duder up ins ../prjs/ko/ins
ev3duder exec 'rm ../prjs/ko/uf2d'
ev3duder up bin/uf2d ../prjs/ko/uf2d
#ev3duder exec 'echo . /mnt/ramdisk/prjs/ko/ins > /mnt/ramdisk/rc.local'

View File

@ -19,6 +19,9 @@
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#define max(a, b) \
({ \
@ -36,7 +39,7 @@
#include "uf2.h"
#define DBG printf
#define DBG LOG
typedef struct {
uint8_t JumpInstruction[3];
@ -332,8 +335,7 @@ void addClusterData(ClusterData *c, FsEntry *e) {
c->myfile = e;
DBG("add cluster: flags=%d size=%d numcl=%d name=%s\n", c->flags, (int)c->st.st_size,
c->numclusters, c->name);
DBG("add cluster: flags=%d size=%d numcl=%d", c->flags, (int)c->st.st_size, c->numclusters);
}
FsEntry *addRootText(const char *filename, const char *contents) {
@ -393,7 +395,7 @@ void setFatNames(FsEntry *dirent) {
}
}
DBG("setname: %s [%s] cl=%s @ %d sz=%d dents=%d\n", p->vfatname, p->fatname,
DBG("setname: %s [%s] cl=%s @ %d sz=%d dents=%d", p->vfatname, p->fatname,
p->data ? p->data->name : "(no data)", p->startCluster, p->size, p->numdirentries);
}
}
@ -528,7 +530,7 @@ void readDirData(uint8_t *dest, FsEntry *dirdata, int blkno) {
if (idx >= 16)
break;
// DBG("dir idx=%d %s\n", idx, e->vfatname);
// DBG("dir idx=%d %s", idx, e->vfatname);
for (int i = 0; i < e->numdirentries; ++i, ++idx) {
if (0 <= idx && idx < 16) {
@ -562,15 +564,15 @@ void readDirData(uint8_t *dest, FsEntry *dirdata, int blkno) {
}
void readBlock(uint8_t *dest, int blkno) {
// DBG("readbl %d\n", blkno);
// DBG("readbl %d", blkno);
int blkno0 = blkno;
for (ClusterData *c = firstCluster; c; c = c->cnext) {
// DBG("off=%d sz=%d\n", blkno, c->numclusters);
// DBG("off=%d sz=%d", blkno, c->numclusters);
if (blkno >= c->numclusters) {
blkno -= c->numclusters;
continue;
}
// DBG("readbl off=%d %p\n", blkno, c);
// DBG("readbl off=%d %p", blkno, c);
if (c->dirdata) {
readDirData(dest, c->dirdata, blkno);
} else if (c->flags & F_TEXT) {
@ -592,6 +594,7 @@ void readBlock(uint8_t *dest, int blkno) {
if (fd >= 0) {
lseek(fd, bl->targetAddr, SEEK_SET);
bl->payloadSize = read(fd, bl->data, 256);
close(fd);
} else {
bl->payloadSize = -1;
}
@ -627,6 +630,48 @@ void read_block(uint32_t block_no, uint8_t *data) {
}
}
char rbfPath[300];
uint8_t stopApp[] = {
0x05, 0x00, // size
0x00, 0x00, // seq. no.
0x3f, 0x3d, // usb magic,
0x02, // req. no.
};
uint8_t runStart[] = {0x00, 0x00, // size
0x00, 0x00, // seq. no.
0x00, 0x00, 0x08, // something
0xC0, 0x08, 0x82, 0x01, 0x00, 0x84};
uint8_t runEnd[] = {0x00, 0x60, 0x64, 0x03, 0x01, 0x60, 0x64, 0x00};
#define FEED_DATA _IOC(_IOC_WRITE, 't', 108, 1024)
void startRbf() {
char buf[1024];
memset(buf, 0, sizeof(buf));
memcpy(buf, stopApp, sizeof(stopApp));
int fd = open("/dev/lms_usbdev", O_RDWR);
ioctl(fd, FEED_DATA, buf);
usleep(500000);
int off = 0;
memcpy(buf + off, runStart, sizeof(runStart));
off += sizeof(runStart);
strcpy(buf + off, rbfPath);
off += strlen(rbfPath);
memcpy(buf + off, runEnd, sizeof(runEnd));
off += sizeof(runEnd);
off -= 2;
buf[0] = off & 0xff;
buf[1] = off >> 8;
ioctl(fd, FEED_DATA, buf);
close(fd);
}
#define MAX_BLOCKS 8000
typedef struct {
uint32_t numBlocks;
@ -634,80 +679,30 @@ typedef struct {
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
} WriteState;
char elfPath[300];
int lmsPid;
void stopLMS() {
struct dirent *ent;
DIR *dir;
dir = opendir("/proc");
if (dir == NULL)
return;
while ((ent = readdir(dir)) != NULL) {
int pid = atoi(ent->d_name);
if (!pid)
continue;
char namebuf[100];
snprintf(namebuf, 1000, "/proc/%d/cmdline", pid);
FILE *f = fopen(namebuf, "r");
if (f) {
fread(namebuf, 1, 99, f);
if (strcmp(namebuf, "./lms2012") == 0) {
lmsPid = pid;
}
fclose(f);
if (lmsPid)
break;
}
}
closedir(dir);
if (lmsPid) {
DBG("SIGSTOP to lmsPID=%d\n", lmsPid);
kill(lmsPid, SIGSTOP);
} else {
DBG("LMS not found\n");
}
}
void waitAndContinue() {
stopLMS();
for (int fd = 3; fd < 9999; ++fd)
close(fd);
pid_t child = fork();
if (child == 0) {
DBG("start %s\n", elfPath);
execl(elfPath, elfPath, "--msd", (char*) NULL);
exit(128);
}
int status;
waitpid(child, &status, 0);
DBG("re-start LMS\n");
if (lmsPid)
kill(lmsPid, SIGCONT);
exit(0);
}
void restartProgram() {
if (!elfPath[0])
if (!rbfPath[0])
exit(0);
pid_t child = fork();
if (child == 0)
waitAndContinue();
else
exit(0); // causes parent to eject MSD etc
startRbf();
exit(0); // causes parent to eject MSD etc
}
int numWrites = 0;
static WriteState wrState;
void write_block(uint32_t block_no, uint8_t *data) {
WriteState *state = &wrState;
UF2_Block *bl = (void *)data;
if (bl->magicStart0 == 0x20da6d81 && bl->magicStart1 == 0x747e09d4) {
DBG("restart req, #wr=%d", numWrites);
if (numWrites) {
exit(0);
}
return;
}
numWrites++;
if (!is_uf2_block(bl)) {
return;
}
@ -746,15 +741,19 @@ void write_block(uint32_t block_no, uint8_t *data) {
*p = '/';
int fd = open(fn, O_WRONLY | O_CREAT, 0777);
if (fd < 0 && errno == ETXTBSY) {
unlink(fn);
fd = open(fn, O_WRONLY | O_CREAT, 0777);
}
if (fd >= 0) {
ftruncate(fd, bl->fileSize);
lseek(fd, bl->targetAddr, SEEK_SET);
// DBG("write %d bytes at %d to %s\n", bl->payloadSize, bl->targetAddr, fn);
// DBG("write %d bytes at %d to %s", bl->payloadSize, bl->targetAddr, fn);
write(fd, bl->data, bl->payloadSize);
close(fd);
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".elf")) {
strcpy(elfPath, fn);
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".rbf")) {
strcpy(rbfPath, fn);
}
}
}
@ -773,6 +772,7 @@ void write_block(uint32_t block_no, uint8_t *data) {
// logval("incr", state->numWritten);
state->writtenMask[pos] |= mask;
state->numWritten++;
DBG("write %d/%d #%d", state->numWritten, state->numBlocks, bl->blockNo);
}
if (state->numWritten >= state->numBlocks) {
restartProgram();

View File

@ -16,27 +16,48 @@
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdarg.h>
#include "uf2.h"
const char *dev_file = "/dev/nbd0";
#define NUM_BLOCKS NUM_FAT_BLOCKS
#define FAIL(args...) \
do { \
fprintf(stderr, args); \
fprintf(stderr, "\n"); \
exit(1); \
} while (0)
#define LOG(args...) \
do { \
fprintf(stderr, args); \
fprintf(stderr, "\n"); \
} while (0)
uint64_t ntohll(uint64_t a) { return ((uint64_t)ntohl(a & 0xffffffff) << 32) | ntohl(a >> 32); }
uint64_t ntohll(uint64_t a) {
return ((uint64_t)ntohl(a & 0xffffffff) << 32) | ntohl(a >> 32);
}
#define htonll ntohll
void mylog(const char *fmt, ...) {
va_list args;
char *p, *p2;
va_start(args, fmt);
vasprintf(&p, fmt, args);
vprintf(fmt, args);
va_end(args);
if (p[0] != '<')
asprintf(&p2, "<6>%s\n", p);
else
asprintf(&p2, "%s\n", p);
int len = strlen(p2);
#ifdef X86
write(2, p2, len);
#else
int fd = open("/dev/kmsg", O_WRONLY);
write(fd, p2, len);
close(fd);
#endif
free(p);
free(p2);
}
void readAll(int fd, void *dst, uint32_t length) {
while (length) {
int curr = read(fd, dst, length);
@ -78,13 +99,10 @@ void startclient() {
exit(0);
}
#define dev_file "/dev/nbd0"
void handleread(int off, int len) {
uint8_t buf[512];
// fprintf(stderr, "read @%d len=%d\n", off, len);
// htonl(EPERM);
reply.error = 0;
LOG("read @%d len=%d", off, len);
reply.error = 0; // htonl(EPERM);
writeAll(sock, &reply, sizeof(struct nbd_reply));
for (int i = 0; i < len; ++i) {
read_block(off + i, buf);
@ -94,7 +112,7 @@ void handleread(int off, int len) {
void handlewrite(int off, int len) {
uint8_t buf[512];
// fprintf(stderr, "write @%d len=%d\n", off, len);
LOG("write @%d len=%d", off, len);
for (int i = 0; i < len; ++i) {
readAll(sock, buf, 512);
write_block(off + i, buf);
@ -133,7 +151,7 @@ void runNBD() {
reply.error = htonl(0);
for (;;) {
nbd_ioctl(BLKFLSBUF, 0); // flush buffers - we don't want the kernel to cache the writes
// nbd_ioctl(BLKFLSBUF, 0); // flush buffers - we don't want the kernel to cache the writes
int nread = read(sock, &request, sizeof(request));
if (nread < 0) {
@ -179,11 +197,14 @@ void enableMSD(int enabled) {
#endif
}
int main() {
int main(int argc, char **argv) {
#ifndef X86
daemon(0, 1);
#endif
if (argc > 1)
dev_file = argv[1];
for (;;) {
pid_t child = fork();
if (child == 0) {

View File

@ -25,8 +25,7 @@ void write_block(uint32_t block_no, uint8_t *data);
#define CONCAT_1(a, b) a##b
#define CONCAT_0(a, b) CONCAT_1(a, b)
#define STATIC_ASSERT(e) \
enum { CONCAT_0(_static_assert_, __LINE__) = 1 / ((e) ? 1 : 0) }
#define STATIC_ASSERT(e) enum { CONCAT_0(_static_assert_, __LINE__) = 1 / ((e) ? 1 : 0) }
extern const char infoUf2File[];
@ -34,4 +33,14 @@ void readAll(int fd, void *dst, uint32_t length);
STATIC_ASSERT(sizeof(UF2_Block) == 512);
void mylog(const char *fmt, ...);
#define FAIL(args...) \
do { \
mylog("<4>" args); \
exit(1); \
} while (0)
#define LOG mylog
#endif

1
docfiles/robotsmeta.html Normal file
View File

@ -0,0 +1 @@
<meta name="robots" content="noindex">

View File

@ -28,20 +28,26 @@ namespace pxt.editor {
let initPromise: Promise<Ev3Wrapper>
function initAsync() {
if (!initPromise)
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
if (!initPromise && Cloud.isLocalHost() && Cloud.localToken && !forceHexDownload)
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
let filename = resp.downloadFileBaseName || "pxt"
filename = filename.replace(/^lego-/, "")
let fspath = "../prjs/BrkProg_SAVE/"
@ -115,13 +121,9 @@ namespace pxt.editor {
const res: pxt.editor.ExtensionResult = {
deployCoreAsync,
};
initAsync()
/*
.then(w => w.streamFileAsync("/tmp/serial.txt", buf => {
let str = Util.fromUTF8(Util.uint8ArrayToString(buf))
}))
*/
initAsync().catch(e => {
// probably no HID - we'll try this again upon deployment
})
return Promise.resolve<pxt.editor.ExtensionResult>(res);
}
}

View File

@ -1,4 +1,37 @@
{
"Array": "Add, remove, and replace items in lists.\n\nAdd, remove, and replace items in lists.",
"Array.filter": "Returns the elements of an array that meet the condition specified in a callback function.",
"Array.filter|param|callbackfn": "A function that accepts up to two arguments. The filter method calls the callbackfn function one time for each element in the array.",
"Array.get": "Gets the value at a particular index",
"Array.get|param|index": "the zero-based position in the list of the item, eg: 0",
"Array.indexOf": "Returns the index of the first occurrence of a value in an array.",
"Array.indexOf|param|fromIndex": "The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.",
"Array.indexOf|param|item": "The value to locate in the array.",
"Array.insertAt": "Insert the value at a particular index, increases length by 1",
"Array.insertAt|param|index": "the zero-based position in the list to insert the value, eg: 0",
"Array.length": "Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.",
"Array.map": "Calls a defined callback function on each element of an array, and returns an array that contains the results.",
"Array.map|param|callbackfn": "A function that accepts up to two arguments. The map method calls the callbackfn function one time for each element in the array.",
"Array.pop": "Removes the last element from an array and returns it.",
"Array.push": "Appends new elements to an array.",
"Array.reduce": "Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.",
"Array.reduce|param|callbackfn": "A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the array.",
"Array.reduce|param|initialValue": "Initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.",
"Array.removeAt": "Removes the object at position index.",
"Array.removeElement": "Removes the first occurence of an object. Returns true if removed.",
"Array.reverse": "Reverses the elements in an Array. The first array element becomes the last, and the last array element becomes the first.",
"Array.set": "Stores the value at a particular index",
"Array.set|param|index": "the zero-based position in the list to store the value, eg: 0",
"Array.shift": "Removes the first element from an array and returns that element. This method changes the length of the array.",
"Array.slice": "Returns a section of an array.",
"Array.slice|param|end": "The end of the specified portion of the array. eg: 0",
"Array.slice|param|start": "The beginning of the specified portion of the array. eg: 0",
"Array.sort": "Sorts the elements of an array in place and returns the array. The sort is not necessarily stable.",
"Array.splice": "Removes elements from an array.",
"Array.splice|param|deleteCount": "The number of elements to remove. eg: 0",
"Array.splice|param|start": "The zero-based location in the array from which to start removing elements. eg: 0",
"Array.unshift": "Adds one element to the beginning of an array and returns the new length of the array.",
"Math": "More complex operations with numbers.",
"Math.abs": "Returns the absolute value of a number (the value without regard to whether it is positive or negative).\nFor example, the absolute value of -5 is the same as the absolute value of 5.",
"Math.abs|param|x": "A numeric expression for which the absolute value is needed.",
"Math.acos": "Returns the arccosine (in radians) of a number",
@ -58,6 +91,7 @@
"Math.tan|param|x": "An angle in radians",
"Math.trunc": "Returns the number with the decimal part truncated.",
"Math.trunc|param|x": "A numeric expression.",
"String": "Combine, split, and search text strings.\n\nCombine, split, and search text strings.",
"String.charAt": "Returns the character at the specified index.",
"String.charAt|param|index": "The zero-based index of the desired character.",
"String.charCodeAt": "Returns the Unicode value of the character at the specified location.",

View File

@ -1,4 +1,14 @@
{
"Array.indexOf|block": "%list| find index of %value",
"Array.insertAt|block": "%list| insert at %index| value %value",
"Array.length|block": "length of %VALUE",
"Array.pop|block": "get and remove last value from %list",
"Array.push|block": "%list| add value %value| to end",
"Array.removeAt|block": "%list| remove value at %index",
"Array.reverse|block": "reverse %list",
"Array.shift|block": "get and remove first value from %list",
"Array.unshift|block": "%list| insert %value| at beginning",
"Array|block": "Array",
"Math.constrain|block": "constrain %value|between %low|and %high",
"Math.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh",
"Math.randomRange|block": "pick random %min|to %limit",
@ -27,6 +37,8 @@
"serial.writeString|block": "serial|write string %text",
"serial.writeValue|block": "serial|write value %name|= %value",
"serial|block": "serial",
"{id:category}Array": "Array",
"{id:category}Arrays": "Arrays",
"{id:category}Control": "Control",
"{id:category}Loops": "Loops",
"{id:category}Math": "Math",

View File

@ -30,7 +30,5 @@
Object = 4,
Function = 5,
}
declare namespace serial {
}
// Auto-generated. Do not edit. Really.

158
libs/base/shims.d.ts vendored Normal file
View File

@ -0,0 +1,158 @@
// Auto-generated. Do not edit.
//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte
declare interface Buffer {
/**
* Write a number in specified format in the buffer.
*/
//% shim=BufferMethods::setNumber
setNumber(format: NumberFormat, offset: int32, value: number): void;
/**
* Read a number in specified format from the buffer.
*/
//% shim=BufferMethods::getNumber
getNumber(format: NumberFormat, offset: int32): number;
/** Returns the length of a Buffer object. */
//% property shim=BufferMethods::length
length: int32;
/**
* Fill (a fragment) of the buffer with given value.
*/
//% offset.defl=0 length.defl=-1 shim=BufferMethods::fill
fill(value: int32, offset?: int32, length?: int32): void;
/**
* Return a copy of a fragment of a buffer.
*/
//% offset.defl=0 length.defl=-1 shim=BufferMethods::slice
slice(offset?: int32, length?: int32): Buffer;
/**
* Shift buffer left in place, with zero padding.
* @param offset number of bytes to shift; use negative value to shift right
* @param start start offset in buffer. Default is 0.
* @param length number of elements in buffer. If negative, length is set as the buffer length minus
* start. eg: -1
*/
//% start.defl=0 length.defl=-1 shim=BufferMethods::shift
shift(offset: int32, start?: int32, length?: int32): void;
/**
* Convert a buffer to its hexadecimal representation.
*/
//% shim=BufferMethods::toHex
toHex(): string;
/**
* Rotate buffer left in place.
* @param offset number of bytes to shift; use negative value to shift right
* @param start start offset in buffer. Default is 0.
* @param length number of elements in buffer. If negative, length is set as the buffer length minus
* start. eg: -1
*/
//% start.defl=0 length.defl=-1 shim=BufferMethods::rotate
rotate(offset: int32, start?: int32, length?: int32): void;
/**
* Write contents of `src` at `dstOffset` in current buffer.
*/
//% shim=BufferMethods::write
write(dstOffset: int32, src: Buffer): void;
}
declare namespace loops {
/**
* Repeats the code forever in the background. On each iteration, allows other codes to run.
* @param body code to execute
*/
//% help=loops/forever weight=100 blockGap=8
//% blockId=forever block="forever" blockAllowMultiple=1 shim=loops::forever
function forever(a: () => void): void;
/**
* Pause for the specified time in milliseconds
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
*/
//% help=loops/pause weight=99
//% async block="pause (ms) %pause"
//% blockId=device_pause shim=loops::pause
function pause(ms: int32): void;
}
declare namespace control {
/**
* Gets the number of milliseconds elapsed since power on.
*/
//% help=control/millis weight=50
//% blockId=control_running_time block="millis (ms)" shim=control::millis
function millis(): int32;
/**
* Run code when a registered event happens.
* @param id the event compoent id
* @param value the event value to match
*/
//% weight=20 blockGap=8 blockId="control_on_event" block="on event|from %src|with value %value"
//% blockExternalInputs=1
//% help="control/on-event" shim=control::onEvent
function onEvent(src: int32, value: int32, handler: () => void): void;
/**
* Reset the device.
*/
//% weight=30 async help=control/reset blockGap=8
//% blockId="control_reset" block="reset" shim=control::reset
function reset(): void;
/**
* Block the current fiber for the given microseconds
* @param micros number of micro-seconds to wait. eg: 4
*/
//% help=control/wait-micros weight=29 async
//% blockId="control_wait_us" block="wait (µs)%micros" shim=control::waitMicros
function waitMicros(micros: int32): void;
/**
* Run other code in the background.
*/
//% help=control/run-in-background blockAllowMultiple=1
//% blockId="control_run_in_background" block="run in background" blockGap=8 shim=control::runInBackground
function runInBackground(a: () => void): void;
/**
* Blocks the calling thread until the specified event is raised.
*/
//% help=control/wait-for-event async
//% blockId=control_wait_for_event block="wait for event|from %src|with value %value" shim=control::waitForEvent
function waitForEvent(src: int32, value: int32): void;
/**
* Derive a unique, consistent serial number of this device from internal data.
*/
//% blockId="control_device_serial_number" block="device serial number" weight=9 shim=control::deviceSerialNumber
function deviceSerialNumber(): int32;
}
declare namespace serial {
/**
* Write some text to the serial port.
*/
//% help=serial/write-string
//% weight=87
//% blockId=serial_writestring block="serial|write string %text" shim=serial::writeString
function writeString(text: string): void;
/**
* Send a buffer across the serial connection.
*/
//% help=serial/write-buffer advanced=true weight=6
//% blockId=serial_writebuffer block="serial|write buffer %buffer" shim=serial::writeBuffer
function writeBuffer(buffer: Buffer): void;
}
// Auto-generated. Do not edit. Really.

View File

@ -20,6 +20,7 @@
"input.remoteTopRight": "Remote top-right button.",
"output.createBuffer": "Create a new zero-initialized buffer.",
"output.createBuffer|param|size": "number of bytes in the buffer",
"output.getPattern": "Pattern block.",
"output.setLights": "Set lights.",
"screen.clear": "Clear screen and reset font to normal.",
"screen.doubleIcon": "Double size of an icon.",

View File

@ -16,7 +16,8 @@
"input.remoteTopLeft|block": "remote top-left",
"input.remoteTopRight|block": "remote top-right",
"input|block": "input",
"output.setLights|block": "set lights %pattern",
"output.getPattern|block": "%pattern",
"output.setLights|block": "set lights %pattern=led_pattern",
"output|block": "output",
"screen|block": "screen",
"serial|block": "serial",

View File

@ -216,8 +216,8 @@ namespace output {
/**
* Set lights.
*/
//% blockId=setLights block="set lights %pattern"
export function setLights(pattern: LightsPattern): void {
//% blockId=setLights block="set lights %pattern=led_pattern"
export function setLights(pattern: number): void {
if (currPattern === pattern)
return
currPattern = pattern
@ -225,4 +225,15 @@ namespace output {
cmd[0] = pattern + 48
input.internal.getBtnsMM().write(cmd)
}
/**
* Pattern block.
*/
//% blockId=led_pattern block="%pattern"
//% shim=TD_ID colorSecondary="#6e9a36"
//% blockHidden=true
export function getPattern(pattern: LightsPattern): number {
return pattern;
}
}

View File

@ -1,6 +1,6 @@
{
"name": "pxt-ev3",
"version": "0.0.0",
"version": "0.0.10",
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
"private": true,
"keywords": [
@ -39,8 +39,8 @@
"semantic-ui-less": "^2.2.4"
},
"dependencies": {
"pxt-common-packages": "0.8.1",
"pxt-core": "1.7.4"
"pxt-common-packages": "0.9.2",
"pxt-core": "2.0.6"
},
"scripts": {
"test": "node node_modules/pxt-core/built/pxt.js travis"

View File

@ -73,10 +73,6 @@ div.blocklyTreeRow {
box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.1);
}
div.blocklyTreeRoot div div div div div.blocklyTreeRow {
padding-top: 0.5rem !important;
}
/* Remove shadow around blockly blocks */
.blocklyPathDark, .blocklyPathLight {
display: none;
@ -98,11 +94,12 @@ span.blocklyTreeLabel {
}
/* Editor menu toggle */
#menubar .ui.menu .item.editor-menuitem {
#menubar .ui.menu.fixed .item.editor-menuitem .ui.grid {
background: @blue !important;
}
#menubar .ui.menu .item.editor-menuitem .item {
color: white !important;
#menubar .ui.menu.fixed .ui.item.editor-menuitem .item:not(.active) {
color: white;
}
/* Search box */
@ -124,11 +121,6 @@ span.blocklyTreeLabel {
#filelist {
background: transparent;
}
div.blocklyTreeRow {
padding-bottom: 2rem !important;
min-height: @blocklyRowHeightMobile;
line-height: @blocklyRowHeightMobile/2;
}
#blocklyTrashIcon {
margin: 0.2rem;
}
@ -136,29 +128,14 @@ span.blocklyTreeLabel {
/* Tablet */
@media only screen and (min-width: @tabletBreakpoint) and (max-width: @largestTabletScreen) {
div.blocklyTreeRow {
padding-left: 0.5rem !important;
min-height: @blocklyRowHeightTablet;
line-height: @blocklyRowHeightTablet/2;
}
}
/* Small Monitor */
@media only screen and (min-width: @computerBreakpoint) and (max-width: @largestSmallMonitor) {
div.blocklyTreeRow {
padding-left: 0.5rem !important;
min-height: @blocklyRowHeightComputer;
line-height: @blocklyRowHeightComputer/2;
}
}
/* Large Monitor */
@media only screen and (min-width: @largeMonitorBreakpoint) {
div.blocklyTreeRow {
padding-left: 0.5rem !important;
min-height: @blocklyRowHeightWide;
line-height: @blocklyRowHeightWide/2;
}
}
/* Mobile, Tablet AND thin screen */
@media only screen and (max-width: @largestTabletScreen) and (max-height: @thinEditorBreakpoint) {