Compare commits
22 Commits
orignalmod
...
v0.0.3
Author | SHA1 | Date | |
---|---|---|---|
f4660b4366 | |||
a4be9f07ea | |||
0c8661808b | |||
b234337dda | |||
c9cdd3112a | |||
fe7e3a8790 | |||
8321c76f4c | |||
227f9614b0 | |||
de0b5f0d86 | |||
abdb21f2a0 | |||
b16f659ea1 | |||
34db42b469 | |||
3edceb248d | |||
8f9b9a5e4e | |||
14783eadc2 | |||
5e7754b436 | |||
c6b4e506d1 | |||
52ef98e249 | |||
9a3eec7d4d | |||
d2f6395443 | |||
7960c9f15e | |||
d84b2b187c |
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -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) {
|
||||
|
@ -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')
|
||||
|
@ -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
14
brick/scripts/README.md
Normal 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
|
53
brick/scripts/ev3-fs.patch
Normal file
53
brick/scripts/ev3-fs.patch
Normal 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
|
@ -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])
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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
1
docfiles/robotsmeta.html
Normal file
@ -0,0 +1 @@
|
||||
<meta name="robots" content="noindex">
|
@ -41,7 +41,8 @@ namespace pxt.editor {
|
||||
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/"
|
||||
|
||||
|
2
libs/base/enums.d.ts
vendored
2
libs/base/enums.d.ts
vendored
@ -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
158
libs/base/shims.d.ts
vendored
Normal 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.
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.0",
|
||||
"version": "0.0.3",
|
||||
"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.1",
|
||||
"pxt-core": "1.8.10"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
@ -98,12 +98,9 @@ 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;
|
||||
}
|
||||
|
||||
/* Search box */
|
||||
#blocklySearchArea {
|
||||
@ -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) {
|
||||
|
Reference in New Issue
Block a user