Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e4e0d8899 | |||
a18a690417 | |||
c9d57c5e8d | |||
7e9d42a571 | |||
1b51320edb | |||
4f44238237 | |||
c8ffa0ded7 | |||
6b07d5f716 | |||
8784e23b60 | |||
4b8409fbc0 | |||
3237978cba | |||
33c8902050 | |||
fa6c81cf80 | |||
46175fc7db | |||
e6ef86101f | |||
c4d3d7634e | |||
b0380fbef8 | |||
c85c68ab68 | |||
334d5aca9a | |||
1330a0fb82 | |||
005447ce44 | |||
60d5271de2 | |||
e3ab6ace55 | |||
5f4488dea7 | |||
07dc3bdae1 | |||
5d5d78ced0 | |||
fe46461c4c | |||
ccda971fd1 | |||
8fa6cf41ca | |||
aa3c6d5fc0 | |||
6a719e7718 | |||
b18b8333d0 | |||
84d80131d4 | |||
4977358718 | |||
15b2ef6c92 | |||
e0288ed741 | |||
df1caf9741 | |||
a755420d06 | |||
a139727fea | |||
48e081e584 | |||
124ad5c915 | |||
75a571fda7 | |||
bb842056d4 | |||
41b023f83f | |||
1ff058460f | |||
cb0895f166 | |||
1340fd0162 | |||
a3f56f4c9a | |||
c0e2252157 | |||
92ad67315b | |||
8b3064f4e0 | |||
138709285a | |||
65dd4617f1 | |||
bdc8c1c62c | |||
ebcde71950 | |||
d42117a2a5 | |||
b0145cf378 | |||
868ee826ab | |||
ce489bba56 | |||
b0944ba431 | |||
8736d32f09 | |||
f8c481555c | |||
15f50966aa | |||
88e21db35e | |||
4e9d3aa413 | |||
1efad776e6 | |||
5e7af872b5 | |||
17683033b1 | |||
31f3d108c5 | |||
b45bf7512c | |||
2dec405a9b | |||
29009aa5e5 | |||
86011827dc | |||
c20cfab069 | |||
197f9096f8 | |||
6d499cb683 | |||
163a4f89f8 | |||
b32aa61cd1 | |||
db7cf212d4 | |||
c8fb59cdde | |||
264156c485 | |||
440dbbe82a | |||
f4660b4366 | |||
a4be9f07ea | |||
0c8661808b | |||
b234337dda |
@ -1,20 +1,20 @@
|
||||
# LEGO Mindstorms EV3 target for PXT
|
||||
|
||||
[](https://ci2.dot.net/job/Private/job/pxt_project_pink/job/master/job/pxt-ev3_Push/)
|
||||
[](https://ci2.dot.net/job/Private/job/pxt_project_rainbow/job/master/job/pxt-ev3_Push/)
|
||||
|
||||
This repo contains the editor target hosted at https://lego.makecode.com
|
||||
This repo contains the editor target hosted at https://d541eec2-1e96-4b7b-a223-da9d01d0337a.pxt.io/
|
||||
|
||||
## Local Dev setup
|
||||
|
||||
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
|
||||
|
@ -1,12 +0,0 @@
|
||||
all: mod uf2
|
||||
|
||||
mod:
|
||||
$(MAKE) -C .. MOD=d_usbdev M=`pwd`/kernel ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
|
||||
@mkdir -p bin
|
||||
cp kernel/*.ko bin/
|
||||
|
||||
uf2:
|
||||
$(MAKE) -C uf2daemon
|
||||
@mkdir -p bin
|
||||
cp uf2daemon/server bin/uf2d
|
||||
|
@ -1,35 +0,0 @@
|
||||
# Support code to run on EV3 brick
|
||||
|
||||
## Kernel module
|
||||
|
||||
Kernel module is based on LEGO's `d_usbdev` module, with the addition of slightly modified `g_mass_storage`
|
||||
module from the Linux kernel. The module and supporting sources are licensed under GPLv2 (since
|
||||
they are derived from GPLv2 code).
|
||||
|
||||
### Modifications
|
||||
|
||||
* 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:
|
||||
* 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
|
||||
|
||||
The kernel itself has modified FIFO queue sizes. The LEGO kernel uses `1024` for `ep1in` and `ep1out`,
|
||||
and then `64` for `ep2` and `ep3`. Note that this is non-standard modification done with a kernel patch,
|
||||
that I didn't manage to find. The MSD requires `512` for `ep2` and `ep3`. I have binary edited the kernel
|
||||
to do so.
|
||||
|
||||
Note that there's 4k of FIFO memory in the hardware. If you set the queue sizes with a sum of more than
|
||||
4k, the kernel will hang, and you will not know why.
|
||||
|
||||
## UF2 Daemon
|
||||
|
||||
The [UF2](https://github.com/Microsoft/uf2) daemon is based on
|
||||
[UF2 ATSAMD21](https://github.com/Microsoft/uf2-samd21) bootloader code. It exposes a virtual
|
||||
FAT16 file system over Linux Network Block Device interface (`/dev/nbd0` to be precise).
|
||||
This device is then exposed via the `g_mass_storage` module to the host computer.
|
||||
|
||||
The Daemon is licensed under MIT.
|
10
brick/ins
10
brick/ins
@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
echo Y > /sys/module/printk/parameters/time
|
||||
cd /mnt/ramdisk/prjs/ko
|
||||
#echo 3 > /proc/sys/kernel/printk
|
||||
insmod ./nbd.ko
|
||||
sleep 1
|
||||
./uf2d /dev/nbd1 > /tmp/uf2d.log 2> /tmp/uf2derr.log
|
||||
sleep 1
|
||||
insmod ./d_usbdev.ko file=/dev/nbd1 HostStr=EV3 SerialStr=0016535543af
|
@ -1,2 +0,0 @@
|
||||
obj-m += $(MOD).o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,762 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This UsbDev file is based on and inheritated from
|
||||
* the original file (zero.c) and work done by David Brownell
|
||||
*
|
||||
* >> zero.c -- Gadget Zero, for USB development <<
|
||||
*
|
||||
* >> Copyright (C) 2003-2008 David Brownell <<
|
||||
* >> Copyright (C) 2008 by Nokia Corporation <<
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \page UsbdevModule USB device Module
|
||||
*
|
||||
*
|
||||
*- \subpage UsbdevModuleResources
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PCASM
|
||||
#include <asm/types.h>
|
||||
#endif
|
||||
|
||||
#include "source/lms2012.h"
|
||||
#include "source/am1808.h"
|
||||
|
||||
|
||||
#define MODULE_NAME "usbdev_module"
|
||||
#define DEVICE1_NAME USBDEV_DEVICE
|
||||
|
||||
|
||||
|
||||
static int ModuleInit(void);
|
||||
static void ModuleExit(void);
|
||||
|
||||
#define __USE_POSIX
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
|
||||
#ifndef PCASM
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
static struct fsg_common *fsg_common;
|
||||
|
||||
#include "computil.c" // The composite framework used as utility file
|
||||
#include <../drivers/usb/gadget/gadget_chips.h>
|
||||
#include <../drivers/usb/gadget/usbstring.c>
|
||||
#include <../drivers/usb/gadget/config.c>
|
||||
#include <../drivers/usb/gadget/epautoconf.c>
|
||||
|
||||
#include "f_mass_storage.c"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#include <../drivers/usb/gadget/g_zero.h>
|
||||
#define MAX_EP_SIZE 1024
|
||||
#define MAX_FULLSPEED_EP_SIZE 64
|
||||
unsigned buflen = MAX_EP_SIZE ;
|
||||
char usb_char_buffer_in[MAX_EP_SIZE];
|
||||
char usb_full_buffer_in[MAX_FULLSPEED_EP_SIZE];
|
||||
int usb_char_in_length = 0;
|
||||
char usb_char_buffer_out[MAX_EP_SIZE];
|
||||
char usb_full_buffer_out[MAX_FULLSPEED_EP_SIZE];
|
||||
int usb_char_out_length = 0;
|
||||
|
||||
#define SHM_LENGTH (sizeof(UsbSpeedDefault))
|
||||
#define NPAGES ((SHM_LENGTH + PAGE_SIZE - 1) / PAGE_SIZE)
|
||||
static void *kmalloc_ptr;
|
||||
|
||||
#include "usb_function.c" // Specific USB functionality
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("The LEGO Group");
|
||||
MODULE_DESCRIPTION(MODULE_NAME);
|
||||
MODULE_SUPPORTED_DEVICE(DEVICE1_NAME);
|
||||
|
||||
module_init(ModuleInit);
|
||||
module_exit(ModuleExit);
|
||||
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
// USB main stuff
|
||||
|
||||
#define DRIVER_VERSION "31jan2011->"
|
||||
|
||||
#ifndef PCASM
|
||||
module_param(buflen, uint, 0);
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
static int loopdefault = 0;
|
||||
#ifndef PCASM
|
||||
module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
#define DRIVER_VENDOR_NUM 0x0694 // LEGO Group
|
||||
#define DRIVER_PRODUCT_NUM 0x0005 // No. 5 in a row
|
||||
#define DEFAULT_AUTORESUME 0
|
||||
|
||||
/* If the optional "autoresume" mode is enabled, it provides good
|
||||
* functional coverage for the "USBCV" test harness from USB-IF.
|
||||
* It's always set if OTG mode is enabled.
|
||||
*/
|
||||
|
||||
unsigned autoresume = DEFAULT_AUTORESUME;
|
||||
module_param(autoresume, uint, S_IRUGO);
|
||||
|
||||
#ifndef PCASM
|
||||
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = 0xEF,
|
||||
.bDeviceSubClass = 2,
|
||||
.bDeviceProtocol = 1,
|
||||
|
||||
/*.bMaxPacketSize0 = f(hardware) */
|
||||
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
struct usb_otg_descriptor otg_descriptor = {
|
||||
.bLength = sizeof otg_descriptor,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
/* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ...
|
||||
*/
|
||||
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
|
||||
};
|
||||
|
||||
const struct usb_descriptor_header *otg_desc[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
NULL,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define STRING_MANUFACTURER_IDX 0
|
||||
#define STRING_PRODUCT_IDX 1
|
||||
#define STRING_SERIAL_IDX 2
|
||||
|
||||
static char manufacturer[] = "LEGO Group";
|
||||
static char serial[] = "123456789ABC ";
|
||||
static char longname[] = "EV3 brick ";
|
||||
|
||||
static struct usb_string strings_dev[3] = {
|
||||
[STRING_MANUFACTURER_IDX].s = manufacturer,
|
||||
[STRING_PRODUCT_IDX].s = longname,
|
||||
[STRING_SERIAL_IDX].s = serial
|
||||
};
|
||||
|
||||
|
||||
static struct usb_gadget_strings stringtab_dev = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings_dev,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *dev_strings[] = {
|
||||
&stringtab_dev,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
req->length = buflen;
|
||||
req->buf = kmalloc(buflen, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
kfree(req->buf);
|
||||
usb_ep_free_request(ep, req);
|
||||
}
|
||||
|
||||
static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (ep->driver_data) {
|
||||
value = usb_ep_disable(ep);
|
||||
if (value < 0)
|
||||
DBG(cdev, "disable %s --> %d\n",
|
||||
ep->name, value);
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void disable_endpoints(struct usb_composite_dev *cdev,
|
||||
struct usb_ep *in, struct usb_ep *out)
|
||||
{
|
||||
disable_ep(cdev, in);
|
||||
disable_ep(cdev, out);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct timer_list autoresume_timer;
|
||||
|
||||
static void zero_autoresume(unsigned long _c)
|
||||
{
|
||||
struct usb_composite_dev *cdev = (void *)_c;
|
||||
struct usb_gadget *g = cdev->gadget;
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_autoresume\n\r");
|
||||
#endif
|
||||
|
||||
/* unconfigured devices can't issue wakeups */
|
||||
if (!cdev->config)
|
||||
return;
|
||||
|
||||
/* Normally the host would be woken up for something
|
||||
* more significant than just a timer firing; likely
|
||||
* because of some direct user request.
|
||||
*/
|
||||
if (g->speed != USB_SPEED_UNKNOWN) {
|
||||
int status = usb_gadget_wakeup(g);
|
||||
INFO(cdev, "%s --> %d\n", __func__, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void zero_suspend(struct usb_composite_dev *cdev)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_suspend\n\r");
|
||||
#endif
|
||||
|
||||
if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
|
||||
return;
|
||||
|
||||
if (autoresume) {
|
||||
mod_timer(&autoresume_timer, jiffies + (HZ * autoresume));
|
||||
DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
|
||||
} else
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static void zero_resume(struct usb_composite_dev *cdev)
|
||||
{
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_resume\n\r");
|
||||
#endif
|
||||
|
||||
del_timer(&autoresume_timer);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int msg_bind(struct usb_composite_dev *cdev);
|
||||
static void msg_bind2(struct usb_composite_dev *cdev);
|
||||
|
||||
static int zero_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
int id;
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
*/
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_dev[STRING_MANUFACTURER_IDX].id = id;
|
||||
device_desc.iManufacturer = id;
|
||||
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
|
||||
strings_dev[STRING_PRODUCT_IDX].id = id;
|
||||
device_desc.iProduct = id;
|
||||
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
|
||||
strings_dev[STRING_SERIAL_IDX].id = id;
|
||||
device_desc.iSerialNumber = id;
|
||||
|
||||
id = msg_bind(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
|
||||
|
||||
rudolf_add(cdev, autoresume != 0);
|
||||
|
||||
gcnum = usb_gadget_controller_number(gadget);
|
||||
if (gcnum >= 0)
|
||||
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
|
||||
else {
|
||||
/* gadget zero is so simple (for now, no altsettings) that
|
||||
* it SHOULD NOT have problems with bulk-capable hardware.
|
||||
* so just warn about unrcognized controllers -- don't panic.
|
||||
*
|
||||
* things like configuration and altsetting numbering
|
||||
* can need hardware-specific attention though.
|
||||
*/
|
||||
pr_warning("%s: controller '%s' not recognized\n",
|
||||
longname, gadget->name);
|
||||
device_desc.bcdDevice = cpu_to_le16(0x9999);
|
||||
}
|
||||
|
||||
msg_bind2(cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zero_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("zero_unbind\n\r");
|
||||
#endif
|
||||
|
||||
del_timer_sync(&autoresume_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_composite_driver zero_driver = {
|
||||
.name = "zero",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = zero_bind,
|
||||
.unbind = zero_unbind,
|
||||
.suspend = zero_suspend,
|
||||
.resume = zero_resume,
|
||||
};
|
||||
|
||||
static int dUsbInit(void)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("dUsbInit\n\r");
|
||||
#endif
|
||||
|
||||
UsbSpeed.Speed = FULL_SPEED; // default to FULL_SPEED if not connected to a HIGH-SPEED
|
||||
(*pUsbSpeed).Speed = FULL_SPEED; // HOST. If not connected to HIGH-SPEED we assume we're
|
||||
// wanting (or at least doing) Daisy Chain
|
||||
return usb_composite_register(&zero_driver);
|
||||
}
|
||||
|
||||
static void dUsbExit(void)
|
||||
{
|
||||
usb_composite_unregister(&zero_driver);
|
||||
}
|
||||
|
||||
// DEVICE1 char device stuff ********************************************************************
|
||||
|
||||
static ssize_t Device1Write(struct file *File,const char *Buffer,size_t Count,loff_t *Data)
|
||||
{
|
||||
// Write data for the HOST to poll - Stuff sent to the HOST
|
||||
|
||||
int BytesWritten = 0;
|
||||
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Device1Write - usb_char_in_length = %d\n", usb_char_in_length);
|
||||
#endif
|
||||
|
||||
if (usb_char_in_length == 0) // ready for more
|
||||
{ // else wait in USER layer
|
||||
BytesWritten = Count;
|
||||
copy_from_user(usb_char_buffer_in, Buffer, BytesWritten);
|
||||
usb_char_in_length = BytesWritten;
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("WR = %d, %d -- ", usb_char_buffer_in[2], usb_char_buffer_in[3]);
|
||||
#endif
|
||||
|
||||
if(USB_DATA_PENDING == input_state)
|
||||
{
|
||||
// Already we've a failed tx (HOST part starwing??
|
||||
|
||||
input_state = USB_DATA_READY;
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("DATA_PENDING SECOND time and reset!! in Device1Write\n\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(USB_DATA_READY == input_state)
|
||||
{
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("USB_DATA_READY in Device1Write\n\r");
|
||||
#endif
|
||||
|
||||
input_state = USB_DATA_BUSY;
|
||||
write_data_to_the_host(save_in_ep, save_in_req);
|
||||
usb_req_arm(save_in_ep, save_in_req); // new request
|
||||
}
|
||||
else
|
||||
{
|
||||
input_state = USB_DATA_PENDING;
|
||||
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("DATA_PENDING in Device1Write\n\r");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("usbdev %d written\n\r", BytesWritten);
|
||||
#endif
|
||||
|
||||
return (BytesWritten); // Zero means USB was not ready yet
|
||||
}
|
||||
|
||||
static ssize_t Device1Read(struct file *File,char *Buffer,size_t Count,loff_t *Offset)
|
||||
{
|
||||
// Read the bits'n'bytes from the HOST
|
||||
int BytesRead = 0;
|
||||
|
||||
if (usb_char_out_length > 0) // Something to look at
|
||||
{
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Some bytes to READ?\n\r");
|
||||
#endif
|
||||
|
||||
copy_to_user(Buffer, usb_char_buffer_out, Count);
|
||||
BytesRead = usb_char_out_length;
|
||||
usb_char_out_length = 0;
|
||||
}
|
||||
return (BytesRead);
|
||||
}
|
||||
|
||||
static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = remap_pfn_range(vma,vma->vm_start,virt_to_phys((void*)((unsigned long)pUsbSpeed)) >> PAGE_SHIFT,vma->vm_end-vma->vm_start,PAGE_SHARED);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
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,
|
||||
.ioctl = Device1Ioctl
|
||||
};
|
||||
|
||||
|
||||
static struct miscdevice Device1 =
|
||||
{
|
||||
MISC_DYNAMIC_MINOR,
|
||||
DEVICE1_NAME,
|
||||
&Device1Entries
|
||||
};
|
||||
|
||||
|
||||
static int Device1Init(void)
|
||||
{
|
||||
int Result = -1;
|
||||
UWORD *pTemp;
|
||||
int i;
|
||||
|
||||
Result = misc_register(&Device1);
|
||||
if (Result)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s device register failed\n",DEVICE1_NAME);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s device register OK\n",DEVICE1_NAME);
|
||||
#endif
|
||||
|
||||
// allocate kernel shared memory for DaisyChain Speed info
|
||||
|
||||
if ((kmalloc_ptr = kmalloc((NPAGES + 2) * PAGE_SIZE, GFP_KERNEL)) != NULL)
|
||||
{
|
||||
|
||||
pTemp = (UWORD*)((((unsigned long)kmalloc_ptr) + PAGE_SIZE - 1) & PAGE_MASK);
|
||||
|
||||
for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
|
||||
{
|
||||
SetPageReserved(virt_to_page(((unsigned long)pTemp) + i));
|
||||
}
|
||||
|
||||
pUsbSpeed = (USB_SPEED*)pTemp;
|
||||
}
|
||||
|
||||
dUsbInit();
|
||||
}
|
||||
|
||||
return (Result);
|
||||
}
|
||||
|
||||
static void Device1Exit(void)
|
||||
{
|
||||
int i;
|
||||
UWORD *pTemp = (UWORD*)pUsbSpeed;
|
||||
|
||||
dUsbExit();
|
||||
|
||||
pUsbSpeed = &UsbSpeedDefault;
|
||||
|
||||
for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE)
|
||||
{
|
||||
ClearPageReserved(virt_to_page(((unsigned long)pTemp) + i));
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s memory page %d unmapped\n",DEVICE1_NAME,i);
|
||||
#endif
|
||||
}
|
||||
|
||||
kfree(kmalloc_ptr);
|
||||
|
||||
misc_deregister(&Device1);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk(" %s device unregistered\n",DEVICE1_NAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// MODULE *********************************************************************
|
||||
|
||||
char *HostStr; // Used for HostName - or NOT used at all
|
||||
char *SerialStr; // Used for Serial number (I.e. BT number)
|
||||
|
||||
module_param (HostStr, charp, 0);
|
||||
module_param (SerialStr, charp, 0);
|
||||
|
||||
static int ModuleInit(void)
|
||||
{
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("%s Module init started\r\n",MODULE_NAME);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("This is DEFAULT NAME: %s\n\r", longname);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the HostStr: %s\n\r", HostStr);
|
||||
#endif
|
||||
|
||||
strcpy(longname, HostStr);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the INSMODed NAME: %s\n\r", longname);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the DEFAULT SerialNumber: %s\n\r", serial);
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the SerialStr: %s\n\r", SerialStr);
|
||||
#endif
|
||||
|
||||
strcpy(serial, SerialStr);
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("\n\rThis is the INSMODed SerialNumber (BT mac): %s\n\r", serial);
|
||||
#endif
|
||||
|
||||
Device1Init();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void ModuleExit(void)
|
||||
{
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("%s exit started\n",MODULE_NAME);
|
||||
#endif
|
||||
|
||||
Device1Exit();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MSG
|
||||
|
||||
|
||||
/****************************** Configurations ******************************/
|
||||
|
||||
static struct fsg_module_parameters fsg_mod_data = {
|
||||
.stall = 1
|
||||
};
|
||||
FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
|
||||
|
||||
/****************************** Gadget Bind ******************************/
|
||||
|
||||
|
||||
static void msg_bind2(struct usb_composite_dev *cdev)
|
||||
{
|
||||
fsg_common_put(fsg_common);
|
||||
}
|
||||
|
||||
static int msg_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
/* set up mass storage function */
|
||||
fsg_common = fsg_common_from_params(0, cdev, &fsg_mod_data);
|
||||
if (IS_ERR(fsg_common)) {
|
||||
return PTR_ERR(fsg_common);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int msg_config(struct usb_configuration *c) {
|
||||
return fsg_add(c->cdev, c, fsg_common);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,276 +0,0 @@
|
||||
/*
|
||||
* USB device controllers have lots of quirks. Use these macros in
|
||||
* gadget drivers or other code that needs to deal with them, and which
|
||||
* autoconfigures instead of using early binding to the hardware.
|
||||
*
|
||||
* This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
|
||||
* some config file that gets updated as new hardware is supported.
|
||||
* (And avoiding all runtime comparisons in typical one-choice configs!)
|
||||
*
|
||||
* NOTE: some of these controller drivers may not be available yet.
|
||||
* Some are available on 2.4 kernels; several are available, but not
|
||||
* yet pushed in the 2.6 mainline tree.
|
||||
*/
|
||||
|
||||
#ifndef __GADGET_CHIPS_H
|
||||
#define __GADGET_CHIPS_H
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_NET2280
|
||||
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
|
||||
#else
|
||||
#define gadget_is_net2280(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_AMD5536UDC
|
||||
#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_amd5536udc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
|
||||
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_dummy(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_PXA25X
|
||||
#define gadget_is_pxa(g) !strcmp("pxa25x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_pxa(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_GOKU
|
||||
#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_goku(g) 0
|
||||
#endif
|
||||
|
||||
/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
|
||||
#ifdef CONFIG_USB_GADGET_SUPERH
|
||||
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_sh(g) 0
|
||||
#endif
|
||||
|
||||
/* not yet stable on 2.6 (would help "original Zaurus") */
|
||||
#ifdef CONFIG_USB_GADGET_SA1100
|
||||
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_sa1100(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_LH7A40X
|
||||
#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_lh7a40x(g) 0
|
||||
#endif
|
||||
|
||||
/* handhelds.org tree (?) */
|
||||
#ifdef CONFIG_USB_GADGET_MQ11XX
|
||||
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_mq11xx(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_OMAP
|
||||
#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_omap(g) 0
|
||||
#endif
|
||||
|
||||
/* not yet ported 2.4 --> 2.6 */
|
||||
#ifdef CONFIG_USB_GADGET_N9604
|
||||
#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_n9604(g) 0
|
||||
#endif
|
||||
|
||||
/* various unstable versions available */
|
||||
#ifdef CONFIG_USB_GADGET_PXA27X
|
||||
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_pxa27x(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_ATMEL_USBA
|
||||
#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_atmel_usba(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_S3C2410
|
||||
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_s3c2410(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_AT91
|
||||
#define gadget_is_at91(g) !strcmp("at91_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_at91(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_IMX
|
||||
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_imx(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_FSL_USB2
|
||||
#define gadget_is_fsl_usb2(g) !strcmp("fsl-usb2-udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_fsl_usb2(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed function controller */
|
||||
/* from Montavista kernel (?) */
|
||||
#ifdef CONFIG_USB_GADGET_MUSBHSFC
|
||||
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhsfc(g) 0
|
||||
#endif
|
||||
|
||||
/* Mentor high speed "dual role" controller, in peripheral role */
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhdrc(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_LANGWELL
|
||||
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_langwell(g) 0
|
||||
#endif
|
||||
|
||||
/* from Montavista kernel (?) */
|
||||
#ifdef CONFIG_USB_GADGET_MPC8272
|
||||
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_mpc8272(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_M66592
|
||||
#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_m66592(g) 0
|
||||
#endif
|
||||
|
||||
/* Freescale CPM/QE UDC SUPPORT */
|
||||
#ifdef CONFIG_USB_GADGET_FSL_QE
|
||||
#define gadget_is_fsl_qe(g) !strcmp("fsl_qe_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_fsl_qe(g) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_CI13XXX
|
||||
#define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name))
|
||||
#else
|
||||
#define gadget_is_ci13xxx(g) 0
|
||||
#endif
|
||||
|
||||
// CONFIG_USB_GADGET_SX2
|
||||
// CONFIG_USB_GADGET_AU1X00
|
||||
// ...
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_R8A66597
|
||||
#define gadget_is_r8a66597(g) !strcmp("r8a66597_udc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_r8a66597(g) 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* usb_gadget_controller_number - support bcdDevice id convention
|
||||
* @gadget: the controller being driven
|
||||
*
|
||||
* Return a 2-digit BCD value associated with the peripheral controller,
|
||||
* suitable for use as part of a bcdDevice value, or a negative error code.
|
||||
*
|
||||
* NOTE: this convention is purely optional, and has no meaning in terms of
|
||||
* any USB specification. If you want to use a different convention in your
|
||||
* gadget driver firmware -- maybe a more formal revision ID -- feel free.
|
||||
*
|
||||
* Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
|
||||
* to change their behavior accordingly. For example it might help avoiding
|
||||
* some chip bug.
|
||||
*/
|
||||
static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
||||
{
|
||||
if (gadget_is_net2280(gadget))
|
||||
return 0x01;
|
||||
else if (gadget_is_dummy(gadget))
|
||||
return 0x02;
|
||||
else if (gadget_is_pxa(gadget))
|
||||
return 0x03;
|
||||
else if (gadget_is_sh(gadget))
|
||||
return 0x04;
|
||||
else if (gadget_is_sa1100(gadget))
|
||||
return 0x05;
|
||||
else if (gadget_is_goku(gadget))
|
||||
return 0x06;
|
||||
else if (gadget_is_mq11xx(gadget))
|
||||
return 0x07;
|
||||
else if (gadget_is_omap(gadget))
|
||||
return 0x08;
|
||||
else if (gadget_is_lh7a40x(gadget))
|
||||
return 0x09;
|
||||
else if (gadget_is_n9604(gadget))
|
||||
return 0x10;
|
||||
else if (gadget_is_pxa27x(gadget))
|
||||
return 0x11;
|
||||
else if (gadget_is_s3c2410(gadget))
|
||||
return 0x12;
|
||||
else if (gadget_is_at91(gadget))
|
||||
return 0x13;
|
||||
else if (gadget_is_imx(gadget))
|
||||
return 0x14;
|
||||
else if (gadget_is_musbhsfc(gadget))
|
||||
return 0x15;
|
||||
else if (gadget_is_musbhdrc(gadget))
|
||||
return 0x16;
|
||||
else if (gadget_is_mpc8272(gadget))
|
||||
return 0x17;
|
||||
else if (gadget_is_atmel_usba(gadget))
|
||||
return 0x18;
|
||||
else if (gadget_is_fsl_usb2(gadget))
|
||||
return 0x19;
|
||||
else if (gadget_is_amd5536udc(gadget))
|
||||
return 0x20;
|
||||
else if (gadget_is_m66592(gadget))
|
||||
return 0x21;
|
||||
else if (gadget_is_fsl_qe(gadget))
|
||||
return 0x22;
|
||||
else if (gadget_is_ci13xxx(gadget))
|
||||
return 0x23;
|
||||
else if (gadget_is_langwell(gadget))
|
||||
return 0x24;
|
||||
else if (gadget_is_r8a66597(gadget))
|
||||
return 0x25;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gadget_supports_altsettings - return true if altsettings work
|
||||
* @gadget: the gadget in question
|
||||
*/
|
||||
static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
|
||||
{
|
||||
/* PXA 21x/25x/26x has no altsettings at all */
|
||||
if (gadget_is_pxa(gadget))
|
||||
return false;
|
||||
|
||||
/* PXA 27x and 3xx have *broken* altsetting support */
|
||||
if (gadget_is_pxa27x(gadget))
|
||||
return false;
|
||||
|
||||
/* SH3 hardware just doesn't do altsettings */
|
||||
if (gadget_is_sh(gadget))
|
||||
return false;
|
||||
|
||||
/* Everything else is *presumably* fine ... */
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __GADGET_CHIPS_H */
|
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AM1808_H_
|
||||
#define AM1808_H_
|
||||
|
||||
#ifndef PCASM
|
||||
#include <mach/da8xx.h>
|
||||
#else
|
||||
#define __iomem
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
GP0_0,GP0_1,GP0_2,GP0_3,GP0_4,GP0_5,GP0_6,GP0_7,GP0_8,GP0_9,GP0_10,GP0_11,GP0_12,GP0_13,GP0_14,GP0_15,
|
||||
GP1_0,GP1_1,GP1_2,GP1_3,GP1_4,GP1_5,GP1_6,GP1_7,GP1_8,GP1_9,GP1_10,GP1_11,GP1_12,GP1_13,GP1_14,GP1_15,
|
||||
GP2_0,GP2_1,GP2_2,GP2_3,GP2_4,GP2_5,GP2_6,GP2_7,GP2_8,GP2_9,GP2_10,GP2_11,GP2_12,GP2_13,GP2_14,GP2_15,
|
||||
GP3_0,GP3_1,GP3_2,GP3_3,GP3_4,GP3_5,GP3_6,GP3_7,GP3_8,GP3_9,GP3_10,GP3_11,GP3_12,GP3_13,GP3_14,GP3_15,
|
||||
GP4_0,GP4_1,GP4_2,GP4_3,GP4_4,GP4_5,GP4_6,GP4_7,GP4_8,GP4_9,GP4_10,GP4_11,GP4_12,GP4_13,GP4_14,GP4_15,
|
||||
GP5_0,GP5_1,GP5_2,GP5_3,GP5_4,GP5_5,GP5_6,GP5_7,GP5_8,GP5_9,GP5_10,GP5_11,GP5_12,GP5_13,GP5_14,GP5_15,
|
||||
GP6_0,GP6_1,GP6_2,GP6_3,GP6_4,GP6_5,GP6_6,GP6_7,GP6_8,GP6_9,GP6_10,GP6_11,GP6_12,GP6_13,GP6_14,GP6_15,
|
||||
GP7_0,GP7_1,GP7_2,GP7_3,GP7_4,GP7_5,GP7_6,GP7_7,GP7_8,GP7_9,GP7_10,GP7_11,GP7_12,GP7_13,GP7_14,GP7_15,
|
||||
GP8_0,GP8_1,GP8_2,GP8_3,GP8_4,GP8_5,GP8_6,GP8_7,GP8_8,GP8_9,GP8_10,GP8_11,GP8_12,GP8_13,GP8_14,GP8_15,
|
||||
NO_OF_GPIOS,
|
||||
UART0_TXD,UART0_RXD,UART1_TXD,UART1_RXD,
|
||||
SPI0_MOSI,SPI0_MISO,SPI0_SCL,SPI0_CS,
|
||||
SPI1_MOSI,SPI1_MISO,SPI1_SCL,SPI1_CS,
|
||||
EPWM1A,EPWM1B,APWM0,APWM1,EPWM0B,AXR3,AXR4
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Pin;
|
||||
u16 MuxReg;
|
||||
u32 Mask;
|
||||
u32 Mode;
|
||||
}
|
||||
MRM;
|
||||
|
||||
MRM MuxRegMap[] =
|
||||
{ // Pin MuxReg Mask Mode
|
||||
|
||||
{ GP0_1 , 1, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP0_2 , 1, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP0_3 , 1, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP0_4 , 1, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP0_5 , 1, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP0_6 , 1, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP0_7 , 1, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP0_11, 0, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP0_12, 0, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP0_13, 0, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP0_14, 0, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP0_15, 0, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP1_0 , 4, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP1_8 , 3, 0xFFFFFFF0, 0x00000004 },
|
||||
|
||||
{ GP1_9, 2, 0xF0FFFFFF, 0x04000000 },
|
||||
{ GP1_10, 2, 0xFF0FFFFF, 0x00400000 },
|
||||
{ GP1_11, 2, 0xFFF0FFFF, 0x00040000 },
|
||||
{ GP1_12, 2, 0xFFFF0FFF, 0x00004000 },
|
||||
{ GP1_13, 2, 0xFFFFF0FF, 0x00000400 },
|
||||
{ GP1_14, 2, 0xFFFFFF0F, 0x00000040 },
|
||||
{ GP1_15, 2, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP2_0, 6, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP2_1, 6, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP2_2, 6, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP2_3, 6, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP2_4, 6, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP2_5, 6, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP2_6, 6, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP2_7, 6, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP2_8, 5, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP2_9, 5, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP2_10, 5, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP2_11, 5, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP2_12, 5, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP2_13, 5, 0xFFFFF0FF, 0x00000800 },
|
||||
|
||||
{ GP3_0, 8, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP3_1 , 8, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP3_2, 8, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP3_3, 8, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP3_4, 8, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP3_5, 8, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP3_6, 8, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP3_7, 8, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP3_8, 7, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP3_9, 7, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP3_10, 7, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP3_11, 7, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP3_12, 7, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP3_13, 7, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP3_14, 7, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP3_15, 7, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP4_1, 10, 0xF0FFFFFF, 0x08000000 },
|
||||
|
||||
{ GP4_8, 9, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP4_9, 9, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP4_10, 9, 0xFF0FFFFF, 0x00800000 },
|
||||
|
||||
{ GP4_12, 9, 0xFFFF0FFF, 0x00008000 },
|
||||
|
||||
{ GP4_14, 9, 0xFFFFFF0F, 0x00000080 },
|
||||
|
||||
{ GP5_0, 12, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP5_1, 12, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP5_2, 12, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP5_3, 12, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP5_4, 12, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP5_5, 12, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP5_6, 12, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP5_7, 12, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP5_8, 11, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP5_9, 11, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP5_10, 11, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP5_11, 11, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP5_12, 11, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP5_13, 11, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP5_14, 11, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP5_15, 11, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP6_0 , 19, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP6_1, 19, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP6_2, 19, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP6_3, 19, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP6_4, 19, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP6_5, 16, 0xFFFFFF0F, 0x00000080 },
|
||||
|
||||
{ GP6_6, 14, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP6_7, 14, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP6_8, 13, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP6_9, 13, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP6_10, 13, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP6_11, 13, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP6_12, 13, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP6_13, 13, 0xFFFFF0FF, 0x00000800 },
|
||||
{ GP6_14, 13, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP6_15, 13, 0xFFFFFFF0, 0x00000008 },
|
||||
|
||||
{ GP7_4, 17, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP7_8, 17, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP7_9, 17, 0xFFFFFFF0, 0x00000008 },
|
||||
{ GP7_10, 16, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP7_11, 16, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP7_12, 16, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP7_13, 16, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP7_14, 16, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP7_15, 16, 0xFFFFF0FF, 0x00000800 },
|
||||
|
||||
{ GP8_2 , 3 , 0xF0FFFFFF, 0x04000000 },
|
||||
{ GP8_3 , 3 , 0xFF0FFFFF, 0x00400000 },
|
||||
{ GP8_5 , 3 , 0xFFFF0FFF, 0x00004000 },
|
||||
{ GP8_6 , 3 , 0xFFFFF0FF, 0x00000400 },
|
||||
{ GP8_8 , 19, 0xFFFFFF0F, 0x00000080 },
|
||||
{ GP8_9 , 19, 0xFFFFFFF0, 0x00000008 },
|
||||
{ GP8_10, 18, 0x0FFFFFFF, 0x80000000 },
|
||||
{ GP8_11, 18, 0xF0FFFFFF, 0x08000000 },
|
||||
{ GP8_12, 18, 0xFF0FFFFF, 0x00800000 },
|
||||
{ GP8_13, 18, 0xFFF0FFFF, 0x00080000 },
|
||||
{ GP8_14, 18, 0xFFFF0FFF, 0x00008000 },
|
||||
{ GP8_15, 18, 0xFFFFF0FF, 0x00000800 },
|
||||
|
||||
|
||||
{ UART0_TXD, 3, 0xFF0FFFFF, 0x00200000 },
|
||||
{ UART0_RXD, 3, 0xFFF0FFFF, 0x00020000 },
|
||||
|
||||
{ UART1_TXD, 4, 0x0FFFFFFF, 0x20000000 },
|
||||
{ UART1_RXD, 4, 0xF0FFFFFF, 0x02000000 },
|
||||
|
||||
{ SPI0_MOSI, 3, 0xFFFF0FFF, 0x00001000 },
|
||||
{ SPI0_MISO, 3, 0xFFFFF0FF, 0x00000100 },
|
||||
{ SPI0_SCL, 3, 0xFFFFFFF0, 0x00000001 },
|
||||
{ SPI0_CS, 3, 0xF0FFFFFF, 0x01000000 },
|
||||
|
||||
{ SPI1_MOSI, 5, 0xFF0FFFFF, 0x00100000 },
|
||||
{ SPI1_MISO, 5, 0xFFF0FFFF, 0x00010000 },
|
||||
{ SPI1_SCL, 5, 0xFFFFF0FF, 0x00000100 },
|
||||
{ SPI1_CS, 5, 0xFFFF0FFF, 0x00008000 },
|
||||
|
||||
{ EPWM1A, 5, 0xFFFFFFF0, 0x00000002 },
|
||||
{ EPWM1B, 5, 0xFFFFFF0F, 0x00000020 },
|
||||
{ APWM0, 2, 0x0FFFFFFF, 0x20000000 },
|
||||
{ APWM1, 1, 0x0FFFFFFF, 0x40000000 },
|
||||
{ EPWM0B, 3, 0xFFFFFF0F, 0x00000020 },
|
||||
|
||||
{ AXR3, 2, 0xFFF0FFFF, 0x00010000 },
|
||||
{ AXR4, 2, 0xFFFF0FFF, 0x00001000 },
|
||||
|
||||
{-1 }
|
||||
};
|
||||
|
||||
typedef struct gpio_controller *__iomem GPIOC;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Pin; // GPIO pin number
|
||||
GPIOC pGpio; // GPIO bank base address
|
||||
u32 Mask; // GPIO pin mask
|
||||
}
|
||||
INPIN;
|
||||
|
||||
#define REGUnlock {\
|
||||
iowrite32(0x83E70B13,da8xx_syscfg0_base + 0x38);\
|
||||
iowrite32(0x95A4F1E0,da8xx_syscfg0_base + 0x3C);\
|
||||
}
|
||||
|
||||
#define REGLock {\
|
||||
iowrite32(0x00000000,da8xx_syscfg0_base + 0x38);\
|
||||
iowrite32(0x00000000,da8xx_syscfg0_base + 0x3C);\
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
extern MRM MuxRegMap[];
|
||||
|
||||
#endif /* AM1808_H_ */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_BRANCH_H_
|
||||
#define C_BRANCH_H_
|
||||
|
||||
void cBranchJr(void);
|
||||
|
||||
void cBranchJrFalse(void);
|
||||
|
||||
void cBranchJrTrue(void);
|
||||
|
||||
void cBranchJrNan(void);
|
||||
|
||||
void cBranchJrLt8(void);
|
||||
|
||||
void cBranchJrLt16(void);
|
||||
|
||||
void cBranchJrLt32(void);
|
||||
|
||||
void cBranchJrLtF(void);
|
||||
|
||||
void cBranchJrGt8(void);
|
||||
|
||||
void cBranchJrGt16(void);
|
||||
|
||||
void cBranchJrGt32(void);
|
||||
|
||||
void cBranchJrGtF(void);
|
||||
|
||||
void cBranchJrLtEq8(void);
|
||||
|
||||
void cBranchJrLtEq16(void);
|
||||
|
||||
void cBranchJrLtEq32(void);
|
||||
|
||||
void cBranchJrLtEqF(void);
|
||||
|
||||
void cBranchJrGtEq8(void);
|
||||
|
||||
void cBranchJrGtEq16(void);
|
||||
|
||||
void cBranchJrGtEq32(void);
|
||||
|
||||
void cBranchJrGtEqF(void);
|
||||
|
||||
void cBranchJrEq8(void);
|
||||
|
||||
void cBranchJrEq16(void);
|
||||
|
||||
void cBranchJrEq32(void);
|
||||
|
||||
void cBranchJrEqF(void);
|
||||
|
||||
void cBranchJrNEq8(void);
|
||||
|
||||
void cBranchJrNEq16(void);
|
||||
|
||||
void cBranchJrNEq32(void);
|
||||
|
||||
void cBranchJrNEqF(void);
|
||||
|
||||
#endif /* C_BRANCH_H_ */
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_COMPARE_H_
|
||||
#define C_COMPARE_H_
|
||||
|
||||
void cCompareLt8(void);
|
||||
|
||||
void cCompareLt16(void);
|
||||
|
||||
void cCompareLt32(void);
|
||||
|
||||
void cCompareLtF(void);
|
||||
|
||||
void cCompareGt8(void);
|
||||
|
||||
void cCompareGt16(void);
|
||||
|
||||
void cCompareGt32(void);
|
||||
|
||||
void cCompareGtF(void);
|
||||
|
||||
void cCompareEq8(void);
|
||||
|
||||
void cCompareEq16(void);
|
||||
|
||||
void cCompareEq32(void);
|
||||
|
||||
void cCompareEqF(void);
|
||||
|
||||
void cCompareNEq8(void);
|
||||
|
||||
void cCompareNEq16(void);
|
||||
|
||||
void cCompareNEq32(void);
|
||||
|
||||
void cCompareNEqF(void);
|
||||
|
||||
void cCompareLtEq8(void);
|
||||
|
||||
void cCompareLtEq16(void);
|
||||
|
||||
void cCompareLtEq32(void);
|
||||
|
||||
void cCompareLtEqF(void);
|
||||
|
||||
void cCompareGtEq8(void);
|
||||
|
||||
void cCompareGtEq16(void);
|
||||
|
||||
void cCompareGtEq32(void);
|
||||
|
||||
void cCompareGtEqF(void);
|
||||
|
||||
void cCompareSelect8(void);
|
||||
|
||||
void cCompareSelect16(void);
|
||||
|
||||
void cCompareSelect32(void);
|
||||
|
||||
void cCompareSelectF(void);
|
||||
|
||||
#endif /* C_COMPARE_H_ */
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_MATH_H_
|
||||
#define C_MATH_H_
|
||||
|
||||
#define DegToRad(D) (D * 0.0174532925)
|
||||
|
||||
#define RadToDeg(R) (R * 57.2957795)
|
||||
|
||||
|
||||
void cMathAdd8(void);
|
||||
|
||||
void cMathAdd16(void);
|
||||
|
||||
void cMathAdd32(void);
|
||||
|
||||
void cMathAddF(void);
|
||||
|
||||
void cMathSub8(void);
|
||||
|
||||
void cMathSub16(void);
|
||||
|
||||
void cMathSub32(void);
|
||||
|
||||
void cMathSubF(void);
|
||||
|
||||
void cMathMul8(void);
|
||||
|
||||
void cMathMul16(void);
|
||||
|
||||
void cMathMul32(void);
|
||||
|
||||
void cMathMulF(void);
|
||||
|
||||
void cMathDiv8(void);
|
||||
|
||||
void cMathDiv16(void);
|
||||
|
||||
void cMathDiv32(void);
|
||||
|
||||
void cMathDivF(void);
|
||||
|
||||
void cMathOr8(void);
|
||||
|
||||
void cMathOr16(void);
|
||||
|
||||
void cMathOr32(void);
|
||||
|
||||
void cMathAnd8(void);
|
||||
|
||||
void cMathAnd16(void);
|
||||
|
||||
void cMathAnd32(void);
|
||||
|
||||
void cMathXor8(void);
|
||||
|
||||
void cMathXor16(void);
|
||||
|
||||
void cMathXor32(void);
|
||||
|
||||
void cMathRl8(void);
|
||||
|
||||
void cMathRl16(void);
|
||||
|
||||
void cMathRl32(void);
|
||||
|
||||
void cMath(void);
|
||||
|
||||
#endif /* C_MATH_H_ */
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_MOVE_H_
|
||||
#define C_MOVE_H_
|
||||
|
||||
void cMove8to8(void);
|
||||
|
||||
void cMove8to16(void);
|
||||
|
||||
void cMove8to32(void);
|
||||
|
||||
void cMove8toF(void);
|
||||
|
||||
void cMove16to8(void);
|
||||
|
||||
void cMove16to16(void);
|
||||
|
||||
void cMove16to32(void);
|
||||
|
||||
void cMove16toF(void);
|
||||
|
||||
void cMove32to8(void);
|
||||
|
||||
void cMove32to16(void);
|
||||
|
||||
void cMove32to32(void);
|
||||
|
||||
void cMove32toF(void);
|
||||
|
||||
void cMoveFto8(void);
|
||||
|
||||
void cMoveFto16(void);
|
||||
|
||||
void cMoveFto32(void);
|
||||
|
||||
void cMoveFtoF(void);
|
||||
|
||||
void cMoveInitBytes(void);
|
||||
|
||||
void cMoveRead8(void);
|
||||
|
||||
void cMoveRead16(void);
|
||||
|
||||
void cMoveRead32(void);
|
||||
|
||||
void cMoveReadF(void);
|
||||
|
||||
void cMoveWrite8(void);
|
||||
|
||||
void cMoveWrite16(void);
|
||||
|
||||
void cMoveWrite32(void);
|
||||
|
||||
void cMoveWriteF(void);
|
||||
|
||||
|
||||
#endif /* C_MOVE_H_ */
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef C_TIMER_H_
|
||||
#define C_TIMER_H_
|
||||
|
||||
#if (HARDWARE != SIMULATION)
|
||||
ULONG cTimerGetuS(void);
|
||||
ULONG cTimerGetmS(void);
|
||||
#endif
|
||||
|
||||
void cTimerWait(void);
|
||||
|
||||
void cTimerReady(void);
|
||||
|
||||
void cTimerRead(void);
|
||||
|
||||
void cTimerReaduS(void);
|
||||
|
||||
#endif /* C_TIMER_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* As a special exception, if other files instantiate templates or use macros or
|
||||
* inline functions from this file, or you compile this file and link it with
|
||||
* other works to produce a work based on this file, this file does not by itself
|
||||
* cause the resulting work to be covered by the GNU General Public License.
|
||||
* However the source code for this file must still be made available in accordance
|
||||
* with section (3) of the GNU General Public License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LMSTYPES_H_
|
||||
#define LMSTYPES_H_
|
||||
|
||||
// BASIC DATA TYPES
|
||||
|
||||
#ifndef LEGO_SIMULATION
|
||||
|
||||
typedef unsigned char UBYTE; //!< Basic Type used to symbolise 8 bit unsigned values
|
||||
typedef unsigned short UWORD; //!< Basic Type used to symbolise 16 bit unsigned values
|
||||
typedef unsigned int ULONG; //!< Basic Type used to symbolise 32 bit unsigned values
|
||||
|
||||
typedef signed char SBYTE; //!< Basic Type used to symbolise 8 bit signed values
|
||||
typedef signed short SWORD; //!< Basic Type used to symbolise 16 bit signed values
|
||||
typedef signed int SLONG; //!< Basic Type used to symbolise 32 bit signed values
|
||||
|
||||
typedef float FLOAT; //!< Basic Type used to symbolise 32 bit floating point values
|
||||
|
||||
#define LFILE FILE
|
||||
|
||||
#else
|
||||
|
||||
#include <Base/BasicTypes.h>
|
||||
#include <VMCalls.h>
|
||||
|
||||
typedef LEGO::UInt8 UBYTE; //!< Basic Type used to symbolise 8 bit unsigned values
|
||||
typedef LEGO::UInt16 UWORD; //!< Basic Type used to symbolise 16 bit unsigned values
|
||||
typedef unsigned long ULONG; //!< Basic Type used to symbolise 32 bit unsigned values
|
||||
|
||||
|
||||
typedef LEGO::Int8 SBYTE; //!< Basic Type used to symbolise 8 bit signed values
|
||||
typedef LEGO::Int16 SWORD; //!< Basic Type used to symbolise 16 bit signed values
|
||||
typedef LEGO::Int32 SLONG; //!< Basic Type used to symbolise 32 bit signed values
|
||||
|
||||
typedef LEGO::Real32 FLOAT; //!< Basic Type used to symbolise 32 bit floating point values
|
||||
|
||||
#endif
|
||||
|
||||
// VM DATA TYPES
|
||||
|
||||
typedef SBYTE DATA8; //!< VM Type for 1 byte signed value
|
||||
typedef SWORD DATA16; //!< VM Type for 2 byte signed value
|
||||
typedef SLONG DATA32; //!< VM Type for 4 byte signed value
|
||||
typedef FLOAT DATAF; //!< VM Type for 4 byte floating point value
|
||||
|
||||
// VM VARIABLE TYPES
|
||||
|
||||
typedef UBYTE VARDATA; //!< Variable base type
|
||||
typedef UBYTE IMGDATA; //!< Image base type
|
||||
|
||||
typedef UWORD PRGID; //!< Program id type
|
||||
|
||||
typedef UWORD OBJID; //!< Object id type
|
||||
typedef IMGDATA* IP; //!< Instruction pointer type
|
||||
typedef VARDATA* LP; //!< Local variable pointer type
|
||||
typedef VARDATA* GP; //!< global variable pointer type
|
||||
|
||||
typedef ULONG IMINDEX; //!< ImageData index type
|
||||
typedef ULONG GBINDEX; //!< GlobalBytes index type
|
||||
typedef ULONG LBINDEX; //!< LocalBytes index type
|
||||
typedef UWORD TRIGGER; //!< TriggerCount type
|
||||
typedef UBYTE PARS; //!< NoOfParameters type
|
||||
typedef SLONG IMOFFS; //!< ImageData offset type
|
||||
|
||||
typedef DATA16 HANDLER; //!< Memory list index
|
||||
|
||||
|
||||
|
||||
/*! \page imagelayout Image Layout
|
||||
* The image consists of three different components in this fixed order: imageheader, objectheaders and byte codes.
|
||||
*
|
||||
* The imageheader tells something about image version, filesize, no of objectheaders (objects) and no of global variable bytes.
|
||||
*
|
||||
*
|
||||
* Objectheaders contains different informations depending on the nature of the object:
|
||||
*
|
||||
*- The VMTHREAD object (former TBC_TOPVI) \n
|
||||
* - OffsetToInstructions tells were to find the corresponding byte codes (offset from image start) \n
|
||||
* - OwnerObjectId must be zero \n
|
||||
* - TriggerCount is used but must be zero \n
|
||||
* - LocalBytes describes the number of bytes for local variables \n
|
||||
*
|
||||
*- The SUBCALL object (former TBC_VI and TBC_VI_ALIAS) \n
|
||||
* - OffsetToInstructions tells were to find the corresponding byte codes (if alias this is equal to mother object) \n
|
||||
* - OwnerObjectId must be zero \n
|
||||
* - TriggerCount is used and must be one \n
|
||||
* - LocalBytes describes the number of bytes for local variables \n
|
||||
*
|
||||
*- The BLOCK object (former CLUMP) \n
|
||||
* - OffsetToInstructions tells were to find the corresponding byte codes (offset from image start) \n
|
||||
* - OwnerObjectId is equal to object id it belongs to (not equal to zero) \n
|
||||
* - TriggerCount is used to determine how many triggers needed before the BLOCK object is activated \n
|
||||
* - LocalBytes must be zero (locals are defined in the owner object) \n
|
||||
*
|
||||
* Byte codes are described in a different section.
|
||||
*
|
||||
* Little Endian are used (addresses and data are represented with LSB on lowest address and MSB on highest address).
|
||||
*
|
||||
* Offset to instructions is number of bytes from start of image to start of object instructions.
|
||||
*
|
||||
* Index to global variables are byte based and counted from start of globals (zero based).
|
||||
*
|
||||
* Index to local variables are byte based and counted from start of object locals (zero based).
|
||||
*
|
||||
* Object ID's is not zero based - First object (VMTHEAD) is named 1.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \page imagelayout
|
||||
*
|
||||
* FILE layout (aligned)
|
||||
*
|
||||
*- IMGHEAD (aligned)
|
||||
* - Sign (4 bytes)
|
||||
* - ImageSize (4 bytes)
|
||||
* - VersionInfo (2 bytes)
|
||||
* - NumberOfObjects (2 bytes)
|
||||
* - GlobalBytes (4 bytes)
|
||||
*/
|
||||
|
||||
/*! \struct IMGHEAD
|
||||
* Image header
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UBYTE Sign[4]; //!< Place holder for the file type identifier
|
||||
IMINDEX ImageSize; //!< Image size
|
||||
UWORD VersionInfo; //!< Version identifier
|
||||
OBJID NumberOfObjects; //!< Total number of objects in image
|
||||
GBINDEX GlobalBytes; //!< Number of bytes to allocate for global variables
|
||||
}
|
||||
IMGHEAD;
|
||||
|
||||
/*! \page imagelayout
|
||||
*
|
||||
*- OBJHEAD (aligned)
|
||||
* - OffsetToInstructions (4 bytes)
|
||||
* - OwnerObjectId (2 bytes)
|
||||
* - TriggerCount (2 bytes)
|
||||
* - LocalBytes (4 bytes)
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \struct OBJHEAD
|
||||
* Object header used for all types of objects (VMTHREAD, SUBCALL, BLOCK and ALIAS)
|
||||
*/
|
||||
typedef struct // Object header
|
||||
{
|
||||
IP OffsetToInstructions; //!< Offset to instructions from image start
|
||||
OBJID OwnerObjectId; //!< Used by BLOCK's to hold the owner id
|
||||
TRIGGER TriggerCount; //!< Used to determine how many triggers needed before the BLOCK object is activated
|
||||
LBINDEX LocalBytes; //!< Number of bytes to allocate for local variables
|
||||
}
|
||||
OBJHEAD;
|
||||
|
||||
|
||||
/*! \struct LABEL
|
||||
* Label data hold information used for labels
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
IMINDEX Addr; //!< Offset to breakpoint address from image start
|
||||
}
|
||||
LABEL;
|
||||
|
||||
|
||||
#endif /* LMSTYPES_H_ */
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VALIDATE_H_
|
||||
#define VALIDATE_H_
|
||||
|
||||
RESULT cValidateInit(void);
|
||||
|
||||
RESULT cValidateExit(void);
|
||||
|
||||
RESULT cValidateDisassemble(IP pI,IMINDEX *pIndex,LABEL *pLabel);
|
||||
|
||||
RESULT cValidateProgram(PRGID PrgId,IP pI,LABEL *pLabel,DATA8 Disassemble);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//*****************************************************************************
|
||||
// Validate Global variables
|
||||
//*****************************************************************************
|
||||
|
||||
int Row;
|
||||
IMINDEX ValidateErrorIndex;
|
||||
}
|
||||
VALIDATE_GLOBALS;
|
||||
|
||||
#ifndef LEGO_SIMULATION
|
||||
extern VALIDATE_GLOBALS ValidateInstance;
|
||||
#else
|
||||
extern VALIDATE_GLOBALS * gValidateInstance;
|
||||
#define ValidateInstance (*gValidateInstance)
|
||||
|
||||
void setValidateInstance(VALIDATE_GLOBALS * _Instance);
|
||||
VALIDATE_GLOBALS * getValidateInstance();
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* VALIDATE_H_ */
|
@ -1,779 +0,0 @@
|
||||
/*
|
||||
* storage_common.c -- Common definitions for mass storage functionality
|
||||
*
|
||||
* Copyright (C) 2003-2008 Alan Stern
|
||||
* Copyeight (C) 2009 Samsung Electronics
|
||||
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file requires the following identifiers used in USB strings to
|
||||
* be defined (each of type pointer to char):
|
||||
* - fsg_string_manufacturer -- name of the manufacturer
|
||||
* - fsg_string_product -- name of the product
|
||||
* - fsg_string_serial -- product's serial
|
||||
* - fsg_string_config -- name of the configuration
|
||||
* - fsg_string_interface -- name of the interface
|
||||
* The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
|
||||
* macro is defined prior to including this file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
|
||||
* fsg_hs_intr_in_desc objects as well as
|
||||
* FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
|
||||
* macros are not defined.
|
||||
*
|
||||
* When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
|
||||
* FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
|
||||
* defined (as well as corresponding entries in string tables are
|
||||
* missing) and FSG_STRING_INTERFACE has value of zero.
|
||||
*
|
||||
* When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
|
||||
* the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
|
||||
* characters rather then a pointer to void.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
/* Thanks to NetChip Technologies for donating this product ID.
|
||||
*
|
||||
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
|
||||
* Instead: allocate your own, using normal USB-IF procedures. */
|
||||
#define FSG_VENDOR_ID 0x0525 /* NetChip */
|
||||
#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef DEBUG
|
||||
#undef VERBOSE_DEBUG
|
||||
#undef DUMP_MSGS
|
||||
#endif /* !DEBUG */
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define VLDBG LDBG
|
||||
#else
|
||||
#define VLDBG(lun, fmt, args...) do { } while (0)
|
||||
#endif /* VERBOSE_DEBUG */
|
||||
|
||||
#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
|
||||
#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
|
||||
#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
|
||||
#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
|
||||
|
||||
/* Keep those macros in sync with thos in
|
||||
* include/linux/ubs/composite.h or else GCC will complain. If they
|
||||
* are identical (the same names of arguments, white spaces in the
|
||||
* same places) GCC will allow redefinition otherwise (even if some
|
||||
* white space is removed or added) warning will be issued. No
|
||||
* checking if those symbols is defined is performed because warning
|
||||
* is desired when those macros were defined by someone else to mean
|
||||
* something else. */
|
||||
#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
|
||||
#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
|
||||
#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
|
||||
#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
|
||||
#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args)
|
||||
|
||||
|
||||
|
||||
#ifdef DUMP_MSGS
|
||||
|
||||
# define dump_msg(fsg, /* const char * */ label, \
|
||||
/* const u8 * */ buf, /* unsigned */ length) do { \
|
||||
if (length < 512) { \
|
||||
DBG(fsg, "%s, length %u:\n", label, length); \
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, buf, length, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define dump_cdb(fsg) do { } while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define dump_msg(fsg, /* const char * */ label, \
|
||||
/* const u8 * */ buf, /* unsigned */ length) do { } while (0)
|
||||
|
||||
# ifdef VERBOSE_DEBUG
|
||||
|
||||
# define dump_cdb(fsg) \
|
||||
print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \
|
||||
16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \
|
||||
|
||||
# else
|
||||
|
||||
# define dump_cdb(fsg) do { } while (0)
|
||||
|
||||
# endif /* VERBOSE_DEBUG */
|
||||
|
||||
#endif /* DUMP_MSGS */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* SCSI device types */
|
||||
#define TYPE_DISK 0x00
|
||||
#define TYPE_CDROM 0x05
|
||||
|
||||
/* USB protocol value = the transport method */
|
||||
#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
|
||||
#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
|
||||
#define USB_PR_BULK 0x50 /* Bulk-only */
|
||||
|
||||
/* USB subclass value = the protocol encapsulation */
|
||||
#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
|
||||
#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
|
||||
#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
|
||||
#define USB_SC_UFI 0x04 /* UFI (floppy) */
|
||||
#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
|
||||
#define USB_SC_SCSI 0x06 /* Transparent SCSI */
|
||||
|
||||
/* Bulk-only data structures */
|
||||
|
||||
/* Command Block Wrapper */
|
||||
struct fsg_bulk_cb_wrap {
|
||||
__le32 Signature; /* Contains 'USBC' */
|
||||
u32 Tag; /* Unique per command id */
|
||||
__le32 DataTransferLength; /* Size of the data */
|
||||
u8 Flags; /* Direction in bit 7 */
|
||||
u8 Lun; /* LUN (normally 0) */
|
||||
u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
|
||||
u8 CDB[16]; /* Command Data Block */
|
||||
};
|
||||
|
||||
#define USB_BULK_CB_WRAP_LEN 31
|
||||
#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
|
||||
#define USB_BULK_IN_FLAG 0x80
|
||||
|
||||
/* Command Status Wrapper */
|
||||
struct bulk_cs_wrap {
|
||||
__le32 Signature; /* Should = 'USBS' */
|
||||
u32 Tag; /* Same as original command */
|
||||
__le32 Residue; /* Amount not transferred */
|
||||
u8 Status; /* See below */
|
||||
};
|
||||
|
||||
#define USB_BULK_CS_WRAP_LEN 13
|
||||
#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
|
||||
#define USB_STATUS_PASS 0
|
||||
#define USB_STATUS_FAIL 1
|
||||
#define USB_STATUS_PHASE_ERROR 2
|
||||
|
||||
/* Bulk-only class specific requests */
|
||||
#define USB_BULK_RESET_REQUEST 0xff
|
||||
#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
|
||||
|
||||
|
||||
/* CBI Interrupt data structure */
|
||||
struct interrupt_data {
|
||||
u8 bType;
|
||||
u8 bValue;
|
||||
};
|
||||
|
||||
#define CBI_INTERRUPT_DATA_LEN 2
|
||||
|
||||
/* CBI Accept Device-Specific Command request */
|
||||
#define USB_CBI_ADSC_REQUEST 0x00
|
||||
|
||||
|
||||
/* Length of a SCSI Command Data Block */
|
||||
#define MAX_COMMAND_SIZE 16
|
||||
|
||||
/* SCSI commands that we recognize */
|
||||
#define SC_FORMAT_UNIT 0x04
|
||||
#define SC_INQUIRY 0x12
|
||||
#define SC_MODE_SELECT_6 0x15
|
||||
#define SC_MODE_SELECT_10 0x55
|
||||
#define SC_MODE_SENSE_6 0x1a
|
||||
#define SC_MODE_SENSE_10 0x5a
|
||||
#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SC_READ_6 0x08
|
||||
#define SC_READ_10 0x28
|
||||
#define SC_READ_12 0xa8
|
||||
#define SC_READ_CAPACITY 0x25
|
||||
#define SC_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SC_READ_HEADER 0x44
|
||||
#define SC_READ_TOC 0x43
|
||||
#define SC_RELEASE 0x17
|
||||
#define SC_REQUEST_SENSE 0x03
|
||||
#define SC_RESERVE 0x16
|
||||
#define SC_SEND_DIAGNOSTIC 0x1d
|
||||
#define SC_START_STOP_UNIT 0x1b
|
||||
#define SC_SYNCHRONIZE_CACHE 0x35
|
||||
#define SC_TEST_UNIT_READY 0x00
|
||||
#define SC_VERIFY 0x2f
|
||||
#define SC_WRITE_6 0x0a
|
||||
#define SC_WRITE_10 0x2a
|
||||
#define SC_WRITE_12 0xaa
|
||||
|
||||
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
|
||||
#define SS_NO_SENSE 0
|
||||
#define SS_COMMUNICATION_FAILURE 0x040800
|
||||
#define SS_INVALID_COMMAND 0x052000
|
||||
#define SS_INVALID_FIELD_IN_CDB 0x052400
|
||||
#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
|
||||
#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
|
||||
#define SS_MEDIUM_NOT_PRESENT 0x023a00
|
||||
#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
|
||||
#define SS_NOT_READY_TO_READY_TRANSITION 0x062800
|
||||
#define SS_RESET_OCCURRED 0x062900
|
||||
#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
|
||||
#define SS_UNRECOVERED_READ_ERROR 0x031100
|
||||
#define SS_WRITE_ERROR 0x030c02
|
||||
#define SS_WRITE_PROTECTED 0x072700
|
||||
|
||||
#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
|
||||
#define ASC(x) ((u8) ((x) >> 8))
|
||||
#define ASCQ(x) ((u8) (x))
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
struct fsg_lun {
|
||||
struct file *filp;
|
||||
loff_t file_length;
|
||||
loff_t num_sectors;
|
||||
|
||||
unsigned int initially_ro:1;
|
||||
unsigned int ro:1;
|
||||
unsigned int removable:1;
|
||||
unsigned int cdrom:1;
|
||||
unsigned int prevent_medium_removal:1;
|
||||
unsigned int registered:1;
|
||||
unsigned int info_valid:1;
|
||||
|
||||
u32 sense_data;
|
||||
u32 sense_data_info;
|
||||
u32 unit_attention_data;
|
||||
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL)
|
||||
|
||||
static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fsg_lun, dev);
|
||||
}
|
||||
|
||||
|
||||
/* Big enough to hold our biggest descriptor */
|
||||
#define EP0_BUFSIZE 256
|
||||
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
|
||||
|
||||
/* Number of buffers we will use. 2 is enough for double-buffering */
|
||||
#define FSG_NUM_BUFFERS 2
|
||||
|
||||
/* Default size of buffer length. */
|
||||
#define FSG_BUFLEN ((u32)16384)
|
||||
|
||||
/* Maximal number of LUNs supported in mass storage function */
|
||||
#define FSG_MAX_LUNS 8
|
||||
|
||||
enum fsg_buffer_state {
|
||||
BUF_STATE_EMPTY = 0,
|
||||
BUF_STATE_FULL,
|
||||
BUF_STATE_BUSY
|
||||
};
|
||||
|
||||
struct fsg_buffhd {
|
||||
#ifdef FSG_BUFFHD_STATIC_BUFFER
|
||||
char buf[FSG_BUFLEN];
|
||||
#else
|
||||
void *buf;
|
||||
#endif
|
||||
enum fsg_buffer_state state;
|
||||
struct fsg_buffhd *next;
|
||||
|
||||
/* The NetChip 2280 is faster, and handles some protocol faults
|
||||
* better, if we don't submit any short bulk-out read requests.
|
||||
* So we will record the intended request length here. */
|
||||
unsigned int bulk_out_intended_length;
|
||||
|
||||
struct usb_request *inreq;
|
||||
int inreq_busy;
|
||||
struct usb_request *outreq;
|
||||
int outreq_busy;
|
||||
};
|
||||
|
||||
enum fsg_state {
|
||||
/* This one isn't used anywhere */
|
||||
FSG_STATE_COMMAND_PHASE = -10,
|
||||
FSG_STATE_DATA_PHASE,
|
||||
FSG_STATE_STATUS_PHASE,
|
||||
|
||||
FSG_STATE_IDLE = 0,
|
||||
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,
|
||||
FSG_STATE_TERMINATED
|
||||
};
|
||||
|
||||
enum data_direction {
|
||||
DATA_DIR_UNKNOWN = 0,
|
||||
DATA_DIR_FROM_HOST,
|
||||
DATA_DIR_TO_HOST,
|
||||
DATA_DIR_NONE
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static inline u32 get_unaligned_be24(u8 *buf)
|
||||
{
|
||||
return 0xffffff & (u32) get_unaligned_be32(buf - 1);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
enum {
|
||||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
FSG_STRING_MANUFACTURER = 1,
|
||||
FSG_STRING_PRODUCT,
|
||||
FSG_STRING_SERIAL,
|
||||
FSG_STRING_CONFIG,
|
||||
#endif
|
||||
FSG_STRING_INTERFACE
|
||||
};
|
||||
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
static struct usb_otg_descriptor
|
||||
fsg_otg_desc = {
|
||||
.bLength = sizeof fsg_otg_desc,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
.bmAttributes = USB_OTG_SRP,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* There is only one interface. */
|
||||
|
||||
static struct usb_interface_descriptor
|
||||
fsg_intf_desc = {
|
||||
.bLength = sizeof fsg_intf_desc,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
.bNumEndpoints = 2, /* Adjusted during fsg_bind() */
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
|
||||
.bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
|
||||
.iInterface = FSG_STRING_INTERFACE,
|
||||
};
|
||||
|
||||
/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
|
||||
* and interrupt-in. */
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
/* wMaxPacketSize set by autoconfiguration */
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
/* wMaxPacketSize set by autoconfiguration */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_intr_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 32, /* frames -> 32 ms */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
|
||||
#else
|
||||
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct usb_descriptor_header *fsg_fs_function[] = {
|
||||
#ifndef FSG_NO_OTG
|
||||
(struct usb_descriptor_header *) &fsg_otg_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &fsg_intf_desc,
|
||||
(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* USB 2.0 devices need to expose both high speed and full speed
|
||||
* descriptors, unless they only run at full speed.
|
||||
*
|
||||
* That means alternate endpoint descriptors (bigger packets)
|
||||
* and a "device qualifier" ... plus more construction options
|
||||
* for the config descriptor.
|
||||
*/
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.bInterval = 1, /* NAK every 1 uframe */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_intr_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
|
||||
#else
|
||||
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct usb_descriptor_header *fsg_hs_function[] = {
|
||||
#ifndef FSG_NO_OTG
|
||||
(struct usb_descriptor_header *) &fsg_otg_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &fsg_intf_desc,
|
||||
(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Maxpacket and other transfer characteristics vary by speed. */
|
||||
static struct usb_endpoint_descriptor *
|
||||
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
|
||||
struct usb_endpoint_descriptor *hs)
|
||||
{
|
||||
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return hs;
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
||||
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
|
||||
static struct usb_string fsg_strings[] = {
|
||||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
{FSG_STRING_MANUFACTURER, fsg_string_manufacturer},
|
||||
{FSG_STRING_PRODUCT, fsg_string_product},
|
||||
{FSG_STRING_SERIAL, fsg_string_serial},
|
||||
{FSG_STRING_CONFIG, fsg_string_config},
|
||||
#endif
|
||||
{FSG_STRING_INTERFACE, fsg_string_interface},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings fsg_stringtab = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = fsg_strings,
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* If the next two routines are called while the gadget is registered,
|
||||
* the caller must own fsg->filesem for writing. */
|
||||
|
||||
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
{
|
||||
int ro;
|
||||
struct file *filp = NULL;
|
||||
int rc = -EINVAL;
|
||||
struct inode *inode = NULL;
|
||||
loff_t size;
|
||||
loff_t num_sectors;
|
||||
loff_t min_sectors;
|
||||
|
||||
/* R/W if we can, R/O if we must */
|
||||
ro = curlun->initially_ro;
|
||||
if (!ro) {
|
||||
filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
|
||||
if (-EROFS == PTR_ERR(filp))
|
||||
ro = 1;
|
||||
}
|
||||
if (ro)
|
||||
filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
|
||||
if (IS_ERR(filp)) {
|
||||
LINFO(curlun, "unable to open backing file: %s\n", filename);
|
||||
return PTR_ERR(filp);
|
||||
}
|
||||
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
ro = 1;
|
||||
|
||||
if (filp->f_path.dentry)
|
||||
inode = filp->f_path.dentry->d_inode;
|
||||
if (inode && S_ISBLK(inode->i_mode)) {
|
||||
if (bdev_read_only(inode->i_bdev))
|
||||
ro = 1;
|
||||
} else if (!inode || !S_ISREG(inode->i_mode)) {
|
||||
LINFO(curlun, "invalid file type: %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we can't read the file, it's no good.
|
||||
* If we can't write the file, use it read-only. */
|
||||
if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
|
||||
LINFO(curlun, "file not readable: %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
if (!(filp->f_op->write || filp->f_op->aio_write))
|
||||
ro = 1;
|
||||
|
||||
size = i_size_read(inode->i_mapping->host);
|
||||
if (size < 0) {
|
||||
LINFO(curlun, "unable to find file size: %s\n", filename);
|
||||
rc = (int) size;
|
||||
goto out;
|
||||
}
|
||||
num_sectors = size >> 9; /* File size in 512-byte blocks */
|
||||
min_sectors = 1;
|
||||
if (curlun->cdrom) {
|
||||
num_sectors &= ~3; /* Reduce to a multiple of 2048 */
|
||||
min_sectors = 300*4; /* Smallest track is 300 frames */
|
||||
if (num_sectors >= 256*60*75*4) {
|
||||
num_sectors = (256*60*75 - 1) * 4;
|
||||
LINFO(curlun, "file too big: %s\n", filename);
|
||||
LINFO(curlun, "using only first %d blocks\n",
|
||||
(int) num_sectors);
|
||||
}
|
||||
}
|
||||
if (num_sectors < min_sectors) {
|
||||
LINFO(curlun, "file too small: %s\n", filename);
|
||||
rc = -ETOOSMALL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
get_file(filp);
|
||||
curlun->ro = ro;
|
||||
curlun->filp = filp;
|
||||
curlun->file_length = size;
|
||||
curlun->num_sectors = num_sectors;
|
||||
LDBG(curlun, "open backing file: %s\n", filename);
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
filp_close(filp, current->files);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void fsg_lun_close(struct fsg_lun *curlun)
|
||||
{
|
||||
if (curlun->filp) {
|
||||
LDBG(curlun, "close backing file\n");
|
||||
fput(curlun->filp);
|
||||
curlun->filp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Sync the file data, don't bother with the metadata.
|
||||
* This code was copied from fs/buffer.c:sys_fdatasync(). */
|
||||
static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
|
||||
{
|
||||
struct file *filp = curlun->filp;
|
||||
|
||||
if (curlun->ro || !filp)
|
||||
return 0;
|
||||
return vfs_fsync(filp, filp->f_path.dentry, 1);
|
||||
}
|
||||
|
||||
static void store_cdrom_address(u8 *dest, int msf, u32 addr)
|
||||
{
|
||||
if (msf) {
|
||||
/* Convert to Minutes-Seconds-Frames */
|
||||
addr >>= 2; /* Convert to 2048-byte frames */
|
||||
addr += 2*75; /* Lead-in occupies 2 seconds */
|
||||
dest[3] = addr % 75; /* Frames */
|
||||
addr /= 75;
|
||||
dest[2] = addr % 60; /* Seconds */
|
||||
addr /= 60;
|
||||
dest[1] = addr; /* Minutes */
|
||||
dest[0] = 0; /* Reserved */
|
||||
} else {
|
||||
/* Absolute sector */
|
||||
put_unaligned_be32(addr, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
|
||||
? curlun->ro
|
||||
: curlun->initially_ro);
|
||||
}
|
||||
|
||||
static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
|
||||
down_read(filesem);
|
||||
if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */
|
||||
p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
|
||||
if (IS_ERR(p))
|
||||
rc = PTR_ERR(p);
|
||||
else {
|
||||
rc = strlen(p);
|
||||
memmove(buf, p, rc);
|
||||
buf[rc] = '\n'; /* Add a newline */
|
||||
buf[++rc] = 0;
|
||||
}
|
||||
} else { /* No file, return 0 bytes */
|
||||
*buf = 0;
|
||||
rc = 0;
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
ssize_t rc = count;
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
if (sscanf(buf, "%d", &i) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Allow the write-enable status to change only while the backing file
|
||||
* is closed. */
|
||||
down_read(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
LDBG(curlun, "read-only status change prevented\n");
|
||||
rc = -EBUSY;
|
||||
} else {
|
||||
curlun->ro = !!i;
|
||||
curlun->initially_ro = !!i;
|
||||
LDBG(curlun, "read-only status set to %d\n", curlun->ro);
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
int rc = 0;
|
||||
|
||||
if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
|
||||
LDBG(curlun, "eject attempt prevented\n");
|
||||
return -EBUSY; /* "Door is locked" */
|
||||
}
|
||||
|
||||
/* Remove a trailing newline */
|
||||
if (count > 0 && buf[count-1] == '\n')
|
||||
((char *) buf)[count-1] = 0; /* Ugh! */
|
||||
|
||||
/* Eject current medium */
|
||||
down_write(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
fsg_lun_close(curlun);
|
||||
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
|
||||
}
|
||||
|
||||
/* Load new medium */
|
||||
if (count > 0 && buf[0]) {
|
||||
rc = fsg_lun_open(curlun, buf);
|
||||
if (rc == 0)
|
||||
curlun->unit_attention_data =
|
||||
SS_NOT_READY_TO_READY_TRANSITION;
|
||||
}
|
||||
up_write(filesem);
|
||||
return (rc < 0 ? rc : count);
|
||||
}
|
@ -1,738 +0,0 @@
|
||||
/*
|
||||
* LEGO® MINDSTORMS EV3
|
||||
*
|
||||
* Copyright (C) 2010-2013 The LEGO Group
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This UsbFunction file is based on and inheritated from
|
||||
* the original file (f_sourcesink.c) and work done by
|
||||
* David Brownell
|
||||
*
|
||||
* >> f_sourcesink.c - USB peripheral source/sink configuration driver <<
|
||||
*
|
||||
* >> Copyright (C) 2003-2008 David Brownell <<
|
||||
* >> Copyright (C) 2008 by Nokia Corporation <<
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* HID IN/OUT Interrupt transfer FUNCTION ...
|
||||
*
|
||||
*/
|
||||
|
||||
struct f_rudolf {
|
||||
struct usb_function function;
|
||||
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_ep *out_ep;
|
||||
};
|
||||
|
||||
enum // Used for signaling the IN stuff USB-state
|
||||
{ // Data from the Brick to the HOST
|
||||
USB_DATA_IDLE, //
|
||||
USB_DATA_BUSY, // Ongoing USB request
|
||||
USB_DATA_PENDING, // Data ready for X-fer, but USB busy
|
||||
USB_DATA_READY, // Initial setting
|
||||
};
|
||||
|
||||
int input_state = USB_DATA_IDLE;
|
||||
struct usb_ep *save_in_ep;
|
||||
struct usb_request *save_in_req;
|
||||
|
||||
#ifndef PCASM
|
||||
static inline struct f_rudolf *func_to_rudolf(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct f_rudolf, function);
|
||||
}
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
static struct usb_interface_descriptor rudolf_intf = {
|
||||
.bLength = sizeof rudolf_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2, // Just plain in and out
|
||||
.bInterfaceClass = USB_CLASS_HID, // We go for NONE custom-driver
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct hid_descriptor hs_hid_rudolf_desc = {
|
||||
.bLength = sizeof hs_hid_rudolf_desc,
|
||||
.bDescriptorType = HID_DT_HID,
|
||||
.bcdHID = cpu_to_le16(0x0110),
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x01, // "The one and only"
|
||||
.desc[0].bDescriptorType = 0x22, // Report Descriptor Type - 0x22 = HID
|
||||
.desc[0].wDescriptorLength = sizeof hs_hid_report_descriptor,
|
||||
/*.desc[0].bDescriptorType = DYNAMIC */
|
||||
/*.desc[0].wDescriptorLenght= DYNAMIC */
|
||||
};
|
||||
|
||||
static struct hid_descriptor fs_hid_rudolf_desc = {
|
||||
.bLength = sizeof fs_hid_rudolf_desc,
|
||||
.bDescriptorType = HID_DT_HID,
|
||||
.bcdHID = cpu_to_le16(0x0110),
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x01, // "The one and only"
|
||||
.desc[0].bDescriptorType = 0x22, // Report Descriptor Type - 0x22 = HID
|
||||
.desc[0].wDescriptorLength = sizeof fs_hid_report_descriptor,
|
||||
|
||||
};
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_out_fs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
.bInterval = 1, /* 1 = 1 mSec POLL rate for FS */
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_in_fs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
.bInterval = 1, /* 1 = 1 mSec POLL rate for FS */
|
||||
};
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_in_hs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 4, /* Calculated as :
|
||||
* 2^(value-1) * 125uS
|
||||
* i.e. value 1: 2^(1-1) * 125 uSec = 125 uSec
|
||||
* - 4: 2^(4-1) * 125 uSec = 1 mSec
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor rudolf_out_hs_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 4, /* Calculated as :
|
||||
* 2^(value-1) * 125uS
|
||||
* i.e. value 1: 2^(1-1) * 125 uSec = 125 uSec
|
||||
* - 4: 2^(4-1) * 125 uSec = 1 mSec
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_rudolf_descs[] = {
|
||||
(struct usb_descriptor_header *) &rudolf_intf,
|
||||
(struct usb_descriptor_header *) &hs_hid_rudolf_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_in_hs_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_out_hs_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *fs_rudolf_descs[] = {
|
||||
(struct usb_descriptor_header *) &rudolf_intf,
|
||||
(struct usb_descriptor_header *) &fs_hid_rudolf_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_in_fs_desc,
|
||||
(struct usb_descriptor_header *) &rudolf_out_fs_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* function-specific strings: */
|
||||
|
||||
static struct usb_string strings_rudolf[] = {
|
||||
[0].s = "Xfer data to and from EV3 brick",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings stringtab_rudolf = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings_rudolf,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *rudolf_strings[] = {
|
||||
&stringtab_rudolf,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int
|
||||
f_rudolf_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_rudolf *rudolf = func_to_rudolf(f);
|
||||
int id;
|
||||
|
||||
/* allocate interface ID(s) */
|
||||
id = usb_interface_id(c, f);
|
||||
if (id < 0)
|
||||
return id;
|
||||
rudolf_intf.bInterfaceNumber = id;
|
||||
|
||||
/* allocate endpoints */
|
||||
rudolf->in_ep = usb_ep_autoconfig(cdev->gadget, &rudolf_in_fs_desc);
|
||||
if (!rudolf->in_ep) {
|
||||
autoconf_fail:
|
||||
ERROR(cdev, "%s: can't autoconfigure on %s\n",
|
||||
f->name, cdev->gadget->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
rudolf->in_ep->driver_data = cdev; /* claim */
|
||||
|
||||
rudolf->out_ep = usb_ep_autoconfig(cdev->gadget, &rudolf_out_fs_desc);
|
||||
if (!rudolf->out_ep)
|
||||
goto autoconf_fail;
|
||||
rudolf->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
|
||||
rudolf_in_hs_desc.bEndpointAddress =
|
||||
rudolf_in_fs_desc.bEndpointAddress;
|
||||
rudolf_out_hs_desc.bEndpointAddress =
|
||||
rudolf_out_fs_desc.bEndpointAddress;
|
||||
f->hs_descriptors = hs_rudolf_descs;
|
||||
f->descriptors = fs_rudolf_descs;
|
||||
}
|
||||
|
||||
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
f->name, rudolf->in_ep->name, rudolf->out_ep->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
f_rudolf_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
kfree(func_to_rudolf(f));
|
||||
}
|
||||
|
||||
static void usb_req_arm(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (UsbSpeed.Speed == FULL_SPEED)
|
||||
{
|
||||
req->length = 64;
|
||||
req->actual = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
req->length = 1024;
|
||||
req->actual = 1024;
|
||||
}
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status) {
|
||||
usb_ep_set_halt(ep);
|
||||
/* FIXME recover later ... somehow */
|
||||
}
|
||||
}
|
||||
|
||||
static int read_data_from_host(struct usb_request *req)
|
||||
{
|
||||
unsigned i;
|
||||
u8 *buf = req->buf;
|
||||
|
||||
int from_host_length = 0; // NO ACCESS LOCKS YET
|
||||
|
||||
// test for actual length > 0
|
||||
|
||||
for (i = 0; i < req->actual; i++, buf++)
|
||||
{
|
||||
|
||||
usb_char_buffer_out[i] = *buf;
|
||||
from_host_length++;
|
||||
}
|
||||
|
||||
return (from_host_length);
|
||||
}
|
||||
|
||||
static void write_data_to_the_host(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
unsigned i;
|
||||
u8 *buf = req->buf;
|
||||
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("WR to HOST req->length = %d\r\n", req->length);
|
||||
#endif
|
||||
|
||||
#undef DEBUG
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("USB = %d, %d\r\n", usb_char_buffer_in[2], usb_char_buffer_in[3]);
|
||||
#endif
|
||||
#undef DEBUG
|
||||
|
||||
for (i = 0; i < req->length; i++)
|
||||
*buf++ = usb_char_buffer_in[i];
|
||||
usb_char_in_length = 0; // Reset and ready
|
||||
}
|
||||
|
||||
static void rudolf_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_rudolf *rudolf = ep->driver_data;
|
||||
int status = req->status;
|
||||
|
||||
|
||||
switch ( status ) {
|
||||
|
||||
case 0: /* normal completion? */
|
||||
if (ep == rudolf->out_ep) // An OUT completion?
|
||||
{
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Rudolf_complete OUT\n");
|
||||
#endif
|
||||
|
||||
usb_char_out_length = read_data_from_host(req);
|
||||
usb_req_arm(ep, req);
|
||||
}
|
||||
else // We have an INPUT request complete
|
||||
{
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("Rudolf_complete IN\n");
|
||||
#endif
|
||||
|
||||
switch(input_state) // State of Brick data x-fer
|
||||
{
|
||||
case USB_DATA_READY: //should be BUSY or PENDING....
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - READY ?????\n");
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case USB_DATA_PENDING: //
|
||||
// #define DEBUG
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - PENDING settes to BUSY\n");
|
||||
#endif
|
||||
|
||||
input_state = USB_DATA_BUSY;
|
||||
write_data_to_the_host(ep, req);
|
||||
usb_req_arm(ep, req); // new request
|
||||
break;
|
||||
|
||||
case USB_DATA_BUSY: //
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - BUSY settes to READY\n");
|
||||
#endif
|
||||
#undef DEBUG
|
||||
input_state = USB_DATA_READY;
|
||||
// and relax
|
||||
break;
|
||||
|
||||
case USB_DATA_IDLE: // too lazy
|
||||
#ifdef DEBUG
|
||||
printk("IN_IN_IN - IDLE\n");
|
||||
#endif
|
||||
//#undef DEBUG
|
||||
|
||||
break;
|
||||
|
||||
default: break; // hmmm.
|
||||
}
|
||||
// Reset the buffer size - Ready again
|
||||
usb_char_in_length = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* this endpoint is normally active while we're configured */
|
||||
|
||||
case -ESHUTDOWN: /* disconnect from host */
|
||||
// REMOVED 26102012 (*pUsbSpeed).Speed = FULL_SPEED;
|
||||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNRESET: /* request dequeued */
|
||||
//case -ESHUTDOWN: /* disconnect from host */
|
||||
if (ep == rudolf->out_ep)
|
||||
read_data_from_host(req);
|
||||
free_ep_req(ep, req);
|
||||
return;
|
||||
|
||||
case -EOVERFLOW: /* buffer overrun on read means that
|
||||
we didn't provide a big enough
|
||||
buffer.
|
||||
*/
|
||||
default:
|
||||
//#if 1
|
||||
// DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
|
||||
// status, req->actual, req->length);
|
||||
//#endif
|
||||
case -EREMOTEIO: /* short read */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int rudolf_start_ep(struct f_rudolf *rudolf, bool is_in)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
struct usb_request *req;
|
||||
int status;
|
||||
|
||||
ep = is_in ? rudolf->in_ep : rudolf->out_ep;
|
||||
req = alloc_ep_req(ep);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->complete = rudolf_complete;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("UsbSpeed.Speed = %d\n\r", UsbSpeed.Speed);
|
||||
#endif
|
||||
|
||||
if (UsbSpeed.Speed == FULL_SPEED)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk("rudolf_start_ep FULL\n\r");
|
||||
#endif
|
||||
|
||||
(*pUsbSpeed).Speed = FULL_SPEED;
|
||||
req->length = 64; // Full speed max buffer size
|
||||
req->actual = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk("rudolf_start_ep HIGH\n\r");
|
||||
#endif
|
||||
|
||||
(*pUsbSpeed).Speed = HIGH_SPEED;
|
||||
req->length = 1024; // High speed max buffer size
|
||||
req->actual = 1024;
|
||||
}
|
||||
|
||||
if (is_in)
|
||||
{
|
||||
save_in_ep = ep;
|
||||
save_in_req = req;
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("req->length = %d ***** Rudolf_Start_Ep_in\n\r", req->length);
|
||||
#endif
|
||||
|
||||
// reinit_write_data(ep, req);
|
||||
input_state = USB_DATA_BUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk("***** Rudolf_Start_Ep_out\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
|
||||
if (status) {
|
||||
struct usb_composite_dev *cdev;
|
||||
|
||||
cdev = rudolf->function.config->cdev;
|
||||
ERROR(cdev, "start %s %s --> %d\n",
|
||||
is_in ? "IN" : "OUT",
|
||||
ep->name, status);
|
||||
|
||||
free_ep_req(ep, req);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void disable_rudolf(struct f_rudolf *rudolf)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
|
||||
cdev = rudolf->function.config->cdev;
|
||||
disable_endpoints(cdev, rudolf->in_ep, rudolf->out_ep);
|
||||
VDBG(cdev, "%s disabled\n", rudolf->function.name);
|
||||
}
|
||||
|
||||
static int
|
||||
enable_rudolf(struct usb_composite_dev *cdev, struct f_rudolf *rudolf)
|
||||
{
|
||||
int result = 0;
|
||||
const struct usb_endpoint_descriptor *ep_in, *ep_out;
|
||||
struct usb_ep *ep;
|
||||
|
||||
ep_in = ep_choose(cdev->gadget, &rudolf_in_hs_desc, &rudolf_in_fs_desc);
|
||||
|
||||
ep_out = ep_choose(cdev->gadget, &rudolf_out_hs_desc, &rudolf_out_fs_desc);
|
||||
|
||||
ep = rudolf->in_ep;
|
||||
|
||||
result = usb_ep_enable(ep, ep_in);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
ep->driver_data = rudolf;
|
||||
|
||||
result = rudolf_start_ep(rudolf, true);
|
||||
|
||||
if (result < 0) {
|
||||
fail:
|
||||
ep = rudolf->in_ep;
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* one endpoint reads (sinks) anything OUT (from the host) */
|
||||
ep = rudolf->out_ep;
|
||||
result = usb_ep_enable(ep, ep_out);
|
||||
|
||||
if (result < 0)
|
||||
goto fail;
|
||||
|
||||
ep->driver_data = rudolf;
|
||||
|
||||
result = rudolf_start_ep(rudolf, false);
|
||||
|
||||
if (result < 0) {
|
||||
usb_ep_disable(ep);
|
||||
ep->driver_data = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DBG(cdev, "%s enabled\n", rudolf->function.name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int f_rudolf_set_alt(struct usb_function *f,
|
||||
unsigned intf, unsigned alt)
|
||||
{
|
||||
struct f_rudolf *rudolf = func_to_rudolf(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
/* we know alt is zero */
|
||||
if (rudolf->in_ep->driver_data)
|
||||
disable_rudolf(rudolf);
|
||||
|
||||
return enable_rudolf(cdev, rudolf);
|
||||
}
|
||||
|
||||
static void f_rudolf_disable(struct usb_function *f)
|
||||
{
|
||||
struct f_rudolf *rudolf = func_to_rudolf(f);
|
||||
|
||||
disable_rudolf(rudolf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int msg_config(struct usb_configuration *c);
|
||||
|
||||
static int rudolf_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_rudolf *rudolf;
|
||||
int status;
|
||||
|
||||
rudolf = kzalloc(sizeof *rudolf, GFP_KERNEL);
|
||||
if (!rudolf)
|
||||
return -ENOMEM;
|
||||
|
||||
rudolf->function.name = "rudolf xfer";
|
||||
rudolf->function.descriptors = hs_rudolf_descs;
|
||||
rudolf->function.bind = f_rudolf_bind;
|
||||
rudolf->function.unbind = f_rudolf_unbind;
|
||||
rudolf->function.set_alt = f_rudolf_set_alt;
|
||||
rudolf->function.disable = f_rudolf_disable;
|
||||
|
||||
status = usb_add_function(c, &rudolf->function);
|
||||
if (status) {
|
||||
kfree(rudolf);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status = msg_config(c);
|
||||
if (status) {
|
||||
kfree(rudolf);
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifndef PCASM
|
||||
static int rudolf_setup(struct usb_configuration *c,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct usb_request *req = c->cdev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
u16 length = 0;
|
||||
|
||||
/* composite driver infrastructure handles everything except
|
||||
* the two control test requests.
|
||||
*/
|
||||
|
||||
switch (ctrl->bRequest) {
|
||||
|
||||
/*
|
||||
* These are the same vendor-specific requests supported by
|
||||
* Intel's USB 2.0 compliance test devices. We exceed that
|
||||
* device spec by allowing multiple-packet requests.
|
||||
*
|
||||
* NOTE: the Control-OUT data stays in req->buf ... better
|
||||
* would be copying it into a scratch buffer, so that other
|
||||
* requests may safely intervene.
|
||||
*/
|
||||
|
||||
case 0x5b: /* control WRITE test -- fill the buffer */
|
||||
if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
|
||||
goto unknown;
|
||||
if (w_value || w_index)
|
||||
break;
|
||||
/* just read that many bytes into the buffer */
|
||||
if (w_length > req->length)
|
||||
break;
|
||||
value = w_length;
|
||||
break;
|
||||
case 0x5c: /* control READ test -- return the buffer */
|
||||
if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
|
||||
goto unknown;
|
||||
if (w_value || w_index)
|
||||
break;
|
||||
/* expect those bytes are still in the buffer; send back */
|
||||
if (w_length > req->length)
|
||||
break;
|
||||
value = w_length;
|
||||
break;
|
||||
|
||||
default:
|
||||
unknown:
|
||||
VDBG(c->cdev,
|
||||
"unknown control req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
}
|
||||
|
||||
//HER SKAL HID DESC SENDES!!!
|
||||
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
||||
|
||||
|
||||
case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
|
||||
| USB_REQ_GET_DESCRIPTOR):
|
||||
switch (w_value >> 8) {
|
||||
case HID_DT_REPORT:
|
||||
//VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
|
||||
length = w_length;
|
||||
length = min_t(unsigned short, length,
|
||||
sizeof hs_hid_report_descriptor);
|
||||
memcpy(req->buf, hs_hid_report_descriptor, length);
|
||||
value = length;
|
||||
goto respond;
|
||||
break;
|
||||
|
||||
default:
|
||||
//VDBG(cdev, "Unknown decriptor request 0x%x\n",
|
||||
// value >> 8);
|
||||
goto stall;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//VDBG(cdev, "Unknown request 0x%x\n",
|
||||
// ctrl->bRequest);
|
||||
goto stall;
|
||||
break;
|
||||
}
|
||||
|
||||
//HERTIL
|
||||
/* respond with data transfer or status phase? */
|
||||
stall:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
respond:
|
||||
if (value >= 0) {
|
||||
VDBG(c->cdev, "source/sink req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
req->zero = 0;
|
||||
req->length = value;
|
||||
value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0)
|
||||
ERROR(c->cdev, "source/sinkc response, err %d\n",
|
||||
value);
|
||||
}
|
||||
|
||||
/* device either stalls (value < 0) or reports success */
|
||||
return value;
|
||||
}
|
||||
#else
|
||||
// Keep Eclipse happy
|
||||
#endif
|
||||
|
||||
static struct usb_configuration rudolf_driver = {
|
||||
.label = "rudolf driver",
|
||||
.strings = rudolf_strings,
|
||||
.bind = rudolf_bind_config,
|
||||
.setup = rudolf_setup,
|
||||
.bConfigurationValue = 1,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
int rudolf_add(struct usb_composite_dev *cdev, bool autoresume)
|
||||
{
|
||||
int id;
|
||||
|
||||
/* allocate string ID(s) */
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
strings_rudolf[0].id = id;
|
||||
|
||||
rudolf_intf.iInterface = id;
|
||||
rudolf_driver.iConfiguration = 1; // id;
|
||||
|
||||
/* support autoresume for remote wakeup testing */
|
||||
if (autoresume)
|
||||
rudolf_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
|
||||
/* support OTG systems */
|
||||
if (gadget_is_otg(cdev->gadget)) {
|
||||
rudolf_driver.descriptors = otg_desc;
|
||||
rudolf_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return usb_add_config(cdev, &rudolf_driver);
|
||||
}
|
7
brick/mk
7
brick/mk
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -xe
|
||||
scp -qr kernel uf2daemon Makefile vm:linux/pxt/
|
||||
ssh vm "cd linux/pxt; make $1"
|
||||
mkdir -p bin
|
||||
scp vm:linux/pxt/bin/* bin/
|
||||
|
@ -1,14 +0,0 @@
|
||||
# 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
|
@ -1,34 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
let fs = require("fs")
|
||||
|
||||
let styles = {
|
||||
"0": "rxtx",
|
||||
"1": " tx",
|
||||
"2": "rx ",
|
||||
}
|
||||
|
||||
function build() {
|
||||
let kern = fs.readFileSync( "foo")
|
||||
let off = 0x0001df30
|
||||
|
||||
kern = kern.slice(off + 6 * 5, off + 6 * (5 + 6))
|
||||
console.log(kern.toString("hex"))
|
||||
off = 0
|
||||
|
||||
for (let i = 0; i < 30; ++i) {
|
||||
if (kern[off+4] == 64) {
|
||||
kern[off+4] = 0
|
||||
kern[off+5] = 2
|
||||
}
|
||||
if(kern[off] == 3 || kern[off] == 4) {
|
||||
kern[off+4] = 0
|
||||
kern[off+5] = 1
|
||||
}
|
||||
console.log(`ep=${kern[off]} style=${styles[kern[off+1]]} buf=${kern[off+2] == 0 ? "sin" : kern[off+2] == 1 ? "dbl" : "XXX"} pad=${kern[off+3]} sz=${kern[off+4]+(kern[off+5]<<8)}`)
|
||||
off += 6
|
||||
}
|
||||
console.log(kern.toString("hex"))
|
||||
}
|
||||
|
||||
build()
|
@ -1,53 +0,0 @@
|
||||
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,55 +0,0 @@
|
||||
#!/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() {
|
||||
if (bootnews.length > bootargs.length) {
|
||||
console.log("args too long")
|
||||
return
|
||||
}
|
||||
|
||||
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])
|
||||
return
|
||||
}
|
||||
|
||||
cr.copy(img, off)
|
||||
|
||||
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])
|
||||
return
|
||||
}
|
||||
|
||||
kern.copy(img, off)
|
||||
|
||||
fs.writeFileSync("firmware.bin", img)
|
||||
}
|
||||
|
||||
build()
|
@ -1,9 +0,0 @@
|
||||
#!/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
|
@ -1,8 +0,0 @@
|
||||
let small = "010100000004010200000004020100004000020200004000030100000004040000008000"
|
||||
let big = "010100000004010200000004020100000002020200000002030100000001040000000001"
|
||||
|
||||
let fs = require("fs")
|
||||
|
||||
let kern = fs.readFileSync( "foo")
|
||||
let kern2 = new Buffer(kern.toString("hex").replace(small, big), "hex")
|
||||
fs.writeFileSync("foo2", kern2)
|
10
brick/send
10
brick/send
@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
./mk
|
||||
ev3duder up bin/d_usbdev.ko ../prjs/ko/d_usbdev.ko
|
||||
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'
|
||||
|
@ -1,6 +0,0 @@
|
||||
CFLAGS = -std=c99 -W -Wall
|
||||
SRC = main.c fat.c
|
||||
|
||||
all:
|
||||
gcc -DX86=1 -g $(CFLAGS) $(SRC) -o server86
|
||||
arm-none-linux-gnueabi-gcc -Os -s $(CFLAGS) $(SRC) -o server
|
@ -1,784 +0,0 @@
|
||||
|
||||
#define VENDOR_NAME "The LEGO Group"
|
||||
#define PRODUCT_NAME "Mindstorms EV3"
|
||||
#define VOLUME_LABEL "EV3"
|
||||
#define INDEX_URL "https://makecode.com/lego"
|
||||
|
||||
#define BOARD_ID "LEGO-EV3-v0"
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define max(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
})
|
||||
|
||||
#define min(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
})
|
||||
|
||||
#include "uf2.h"
|
||||
|
||||
#define DBG LOG
|
||||
|
||||
typedef struct {
|
||||
uint8_t JumpInstruction[3];
|
||||
uint8_t OEMInfo[8];
|
||||
uint16_t SectorSize;
|
||||
uint8_t SectorsPerCluster;
|
||||
uint16_t ReservedSectors;
|
||||
uint8_t FATCopies;
|
||||
uint16_t RootDirectoryEntries;
|
||||
uint16_t TotalSectors16;
|
||||
uint8_t MediaDescriptor;
|
||||
uint16_t SectorsPerFAT;
|
||||
uint16_t SectorsPerTrack;
|
||||
uint16_t Heads;
|
||||
uint32_t HiddenSectors;
|
||||
uint32_t TotalSectors32;
|
||||
uint8_t PhysicalDriveNum;
|
||||
uint8_t Reserved;
|
||||
uint8_t ExtendedBootSig;
|
||||
uint32_t VolumeSerialNumber;
|
||||
char VolumeLabel[11];
|
||||
uint8_t FilesystemIdentifier[8];
|
||||
} __attribute__((packed)) FAT_BootBlock;
|
||||
|
||||
typedef struct {
|
||||
char name[8];
|
||||
char ext[3];
|
||||
uint8_t attrs;
|
||||
uint8_t reserved;
|
||||
uint8_t createTimeFine;
|
||||
uint16_t createTime;
|
||||
uint16_t createDate;
|
||||
uint16_t lastAccessDate;
|
||||
uint16_t highStartCluster;
|
||||
uint16_t updateTime;
|
||||
uint16_t updateDate;
|
||||
uint16_t startCluster;
|
||||
uint32_t size;
|
||||
} __attribute__((packed)) DirEntry;
|
||||
|
||||
typedef struct {
|
||||
uint8_t seqno;
|
||||
uint16_t name0[5];
|
||||
uint8_t attrs;
|
||||
uint8_t type;
|
||||
uint8_t checksum;
|
||||
uint16_t name1[6];
|
||||
uint16_t startCluster;
|
||||
uint16_t name2[2];
|
||||
} __attribute__((packed)) VFatEntry;
|
||||
|
||||
STATIC_ASSERT(sizeof(DirEntry) == 32);
|
||||
|
||||
#define STR0(x) #x
|
||||
#define STR(x) STR0(x)
|
||||
const char infoUf2File[] = //
|
||||
"UF2 Bootloader " UF2_VERSION "\r\n"
|
||||
"Model: " PRODUCT_NAME "\r\n"
|
||||
"Board-ID: " BOARD_ID "\r\n";
|
||||
|
||||
const char indexFile[] = //
|
||||
"<!doctype html>\n"
|
||||
"<html>"
|
||||
"<body>"
|
||||
"<script>\n"
|
||||
"location.replace(\"" INDEX_URL "\");\n"
|
||||
"</script>"
|
||||
"</body>"
|
||||
"</html>\n";
|
||||
|
||||
#define RESERVED_SECTORS 1
|
||||
#define ROOT_DIR_SECTORS 4
|
||||
#define SECTORS_PER_FAT ((NUM_FAT_BLOCKS * 2 + 511) / 512)
|
||||
|
||||
#define START_FAT0 RESERVED_SECTORS
|
||||
#define START_FAT1 (START_FAT0 + SECTORS_PER_FAT)
|
||||
#define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT)
|
||||
#define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
|
||||
#define ROOT_DIR_ENTRIES (ROOT_DIR_SECTORS * 512 / 32)
|
||||
|
||||
#define F_TEXT 1
|
||||
#define F_UF2 2
|
||||
#define F_DIR 4
|
||||
#define F_CONT 8
|
||||
|
||||
static const FAT_BootBlock BootBlock = {
|
||||
.JumpInstruction = {0xeb, 0x3c, 0x90},
|
||||
.OEMInfo = "UF2 UF2 ",
|
||||
.SectorSize = 512,
|
||||
.SectorsPerCluster = 1,
|
||||
.ReservedSectors = RESERVED_SECTORS,
|
||||
.FATCopies = 2,
|
||||
.RootDirectoryEntries = ROOT_DIR_ENTRIES,
|
||||
.TotalSectors16 = NUM_FAT_BLOCKS - 2,
|
||||
.MediaDescriptor = 0xF8,
|
||||
.SectorsPerFAT = SECTORS_PER_FAT,
|
||||
.SectorsPerTrack = 1,
|
||||
.Heads = 1,
|
||||
.ExtendedBootSig = 0x29,
|
||||
.VolumeSerialNumber = 0x00420042,
|
||||
.VolumeLabel = VOLUME_LABEL,
|
||||
.FilesystemIdentifier = "FAT16 ",
|
||||
};
|
||||
|
||||
int currCluster = 2;
|
||||
struct FsEntry *rootDir;
|
||||
struct ClusterData *firstCluster, *lastCluster;
|
||||
|
||||
typedef struct ClusterData {
|
||||
int flags;
|
||||
int numclusters;
|
||||
struct stat st;
|
||||
struct ClusterData *dnext;
|
||||
struct ClusterData *cnext;
|
||||
struct FsEntry *dirdata;
|
||||
struct FsEntry *myfile;
|
||||
char name[0];
|
||||
} ClusterData;
|
||||
|
||||
typedef struct FsEntry {
|
||||
int startCluster;
|
||||
uint8_t attrs;
|
||||
int size;
|
||||
int numdirentries;
|
||||
time_t ctime, mtime;
|
||||
struct FsEntry *next;
|
||||
struct ClusterData *data;
|
||||
char fatname[12];
|
||||
char vfatname[0];
|
||||
} FsEntry;
|
||||
|
||||
struct DirMap {
|
||||
const char *mapName;
|
||||
const char *fsName;
|
||||
};
|
||||
|
||||
struct DirMap dirMaps[] = { //
|
||||
#ifdef X86
|
||||
{"foo qux baz", "dirs/bar"}, //
|
||||
{"foo", "dirs/foo"}, //
|
||||
{"xyz", "dirs/bar2"}, //
|
||||
#else
|
||||
{"Projects", "/mnt/ramdisk/prjs/BrkProg_SAVE"},
|
||||
{"SD Card", "/media/card/myapps"},
|
||||
{"USB Stick", "/media/usb/myapps"},
|
||||
#endif
|
||||
{NULL, NULL}};
|
||||
|
||||
void timeToFat(time_t t, uint16_t *dateP, uint16_t *timeP) {
|
||||
struct tm tm;
|
||||
|
||||
localtime_r(&t, &tm);
|
||||
|
||||
if (timeP)
|
||||
*timeP = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec / 2);
|
||||
|
||||
if (dateP)
|
||||
*dateP = (max(0, tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday;
|
||||
}
|
||||
|
||||
void padded_memcpy(char *dst, const char *src, int len) {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (*src)
|
||||
*dst = *src++;
|
||||
else
|
||||
*dst = ' ';
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
char *expandMap(const char *mapName) {
|
||||
static char mapbuf[300];
|
||||
|
||||
const char *rest = "";
|
||||
for (int i = 0; i < (int)sizeof(mapbuf); ++i) {
|
||||
char c = mapName[i];
|
||||
if (c == '/' || c == 0) {
|
||||
mapbuf[i] = 0;
|
||||
rest = mapName + i;
|
||||
break;
|
||||
}
|
||||
mapbuf[i] = c;
|
||||
}
|
||||
for (int i = 0; dirMaps[i].mapName; ++i) {
|
||||
if (strcmp(dirMaps[i].mapName, mapbuf) == 0) {
|
||||
strcpy(mapbuf, dirMaps[i].fsName);
|
||||
strcat(mapbuf, rest);
|
||||
return mapbuf;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClusterData *mkClusterData(int namelen) {
|
||||
ClusterData *c = malloc(sizeof(*c) + namelen + 1);
|
||||
memset(c, 0, sizeof(*c) + namelen + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
ClusterData *readDir(const char *mapName) {
|
||||
DIR *d = opendir(expandMap(mapName));
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
ClusterData *res = NULL;
|
||||
for (;;) {
|
||||
struct dirent *ent = readdir(d);
|
||||
if (!ent)
|
||||
break;
|
||||
|
||||
ClusterData *c = mkClusterData(strlen(mapName) + 1 + strlen(ent->d_name));
|
||||
|
||||
c->flags = F_UF2;
|
||||
c->dnext = res;
|
||||
sprintf(c->name, "%s/%s", mapName, ent->d_name);
|
||||
|
||||
int err = stat(expandMap(c->name), &c->st);
|
||||
assert(err >= 0);
|
||||
|
||||
if (S_ISREG(c->st.st_mode) && strlen(c->name) < UF2_FILENAME_MAX) {
|
||||
c->numclusters = (c->st.st_size + 255) / 256;
|
||||
} else {
|
||||
free(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = c;
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return res;
|
||||
}
|
||||
|
||||
int filechar(int c) {
|
||||
if (!c)
|
||||
return 0;
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
|
||||
strchr("_-", c);
|
||||
}
|
||||
|
||||
void copyFsChars(char *dst, const char *src, int len) {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (filechar(*src))
|
||||
dst[i] = toupper(*src++);
|
||||
else {
|
||||
if (*src == '.')
|
||||
src = "";
|
||||
if (*src == 0)
|
||||
dst[i] = ' ';
|
||||
else
|
||||
dst[i] = '_';
|
||||
while (*src && !filechar(*src))
|
||||
src++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FsEntry *mkFsEntry(const char *name) {
|
||||
int sz = sizeof(FsEntry) + strlen(name) + 1;
|
||||
FsEntry *e = malloc(sz);
|
||||
memset(e, 0, sz);
|
||||
e->startCluster = currCluster;
|
||||
e->next = NULL;
|
||||
// +1 for final 0x0000, and +12 for alignment
|
||||
e->numdirentries = 1 + (strlen(name) + 1 + 12) / 13;
|
||||
strcpy(e->vfatname, name);
|
||||
|
||||
const char *src = name;
|
||||
copyFsChars(e->fatname, src, 8);
|
||||
while (*src && *src != '.')
|
||||
src++;
|
||||
if (*src == '.')
|
||||
src++;
|
||||
else
|
||||
src = "";
|
||||
copyFsChars(e->fatname + 8, src, 3);
|
||||
return e;
|
||||
}
|
||||
|
||||
void addClusterData(ClusterData *c, FsEntry *e) {
|
||||
currCluster += c->numclusters;
|
||||
|
||||
if (firstCluster == NULL) {
|
||||
firstCluster = c;
|
||||
} else {
|
||||
lastCluster->cnext = c;
|
||||
}
|
||||
lastCluster = c;
|
||||
|
||||
if (c->st.st_ctime)
|
||||
e->ctime = min(e->ctime, c->st.st_ctime);
|
||||
e->mtime = max(e->mtime, c->st.st_mtime);
|
||||
|
||||
c->myfile = e;
|
||||
|
||||
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) {
|
||||
FsEntry *e = mkFsEntry(filename);
|
||||
e->next = rootDir;
|
||||
rootDir = e;
|
||||
|
||||
int sz = strlen(contents);
|
||||
e->size = sz;
|
||||
if (sz > 0) {
|
||||
assert(sz <= 512);
|
||||
ClusterData *c = mkClusterData(sz);
|
||||
c->st.st_mtime = c->st.st_ctime = time(NULL);
|
||||
|
||||
c->flags = F_TEXT;
|
||||
strcpy(c->name, contents);
|
||||
c->st.st_size = sz;
|
||||
c->numclusters = 1;
|
||||
addClusterData(c, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
int baseLen(const char *a) {
|
||||
int len = 0;
|
||||
while (*a && *a != '.') {
|
||||
a++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int nameMatches(const char *a, const char *b) {
|
||||
for (;;) {
|
||||
if ((*a == 0 || *a == '.') && (*b == 0 || *b == '.'))
|
||||
return 1;
|
||||
|
||||
if (*a != *b)
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
}
|
||||
|
||||
void setFatNames(FsEntry *dirent) {
|
||||
for (FsEntry *p = dirent; p; p = p->next) {
|
||||
// check for collisions
|
||||
int k = 1;
|
||||
retry:
|
||||
for (FsEntry *o = dirent; o && o != p; o = o->next) {
|
||||
if (strcmp(o->fatname, p->fatname) == 0) {
|
||||
char buf[20];
|
||||
sprintf(buf, "~%d", k++);
|
||||
int len = strlen(buf);
|
||||
memcpy(p->fatname + 8 - len, buf, len);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void addFullDir(const char *mapName) {
|
||||
int numEntries = 0;
|
||||
FsEntry *dirents = NULL;
|
||||
|
||||
time_t mtime = 0, ctime = 0;
|
||||
|
||||
for (ClusterData *cl = readDir(mapName); cl; cl = cl->dnext) {
|
||||
if (cl->cnext || cl == lastCluster)
|
||||
continue; // already done
|
||||
|
||||
// vfat entries
|
||||
const char *filename = strchr(cl->name, '/') + 1;
|
||||
int len = baseLen(filename) + 4;
|
||||
char namebuf[len];
|
||||
memcpy(namebuf, filename, len - 4);
|
||||
strcpy(namebuf + len - 4, ".uf2");
|
||||
|
||||
assert(cl->flags & F_UF2);
|
||||
|
||||
FsEntry *fent = mkFsEntry(namebuf);
|
||||
numEntries += fent->numdirentries;
|
||||
fent->next = dirents;
|
||||
fent->data = cl;
|
||||
fent->size = cl->numclusters * 512;
|
||||
dirents = fent;
|
||||
addClusterData(cl, fent);
|
||||
for (ClusterData *other = cl->dnext; other; other = other->dnext) {
|
||||
if (nameMatches(cl->name, other->name)) {
|
||||
other->flags |= F_CONT;
|
||||
fent->size += other->numclusters * 512;
|
||||
addClusterData(other, fent);
|
||||
}
|
||||
}
|
||||
if (mtime == 0) {
|
||||
mtime = fent->mtime;
|
||||
ctime = fent->ctime;
|
||||
} else {
|
||||
mtime = max(mtime, fent->mtime);
|
||||
ctime = min(ctime, fent->ctime);
|
||||
}
|
||||
}
|
||||
|
||||
setFatNames(dirents);
|
||||
|
||||
FsEntry *dent = mkFsEntry(mapName);
|
||||
dent->data = mkClusterData(0);
|
||||
dent->data->dirdata = dirents;
|
||||
dent->data->numclusters = (numEntries + 16) / 16; // at least 1
|
||||
addClusterData(dent->data, dent);
|
||||
dent->mtime = mtime;
|
||||
dent->ctime = ctime;
|
||||
dent->next = rootDir;
|
||||
dent->attrs = 0x10;
|
||||
dent->data->flags = F_DIR;
|
||||
rootDir = dent;
|
||||
}
|
||||
|
||||
void setupFs() {
|
||||
addRootText("info_uf2.txt", infoUf2File);
|
||||
addRootText("index.html", indexFile);
|
||||
for (int i = 0; dirMaps[i].mapName; ++i) {
|
||||
addFullDir(dirMaps[i].mapName);
|
||||
}
|
||||
|
||||
setFatNames(rootDir); // make names unique
|
||||
|
||||
FsEntry *e = addRootText(BootBlock.VolumeLabel, "");
|
||||
e->numdirentries = 1;
|
||||
e->attrs = 0x28;
|
||||
}
|
||||
|
||||
#define WRITE_ENT(v) \
|
||||
do { \
|
||||
if (skip++ >= 0) \
|
||||
*dest++ = v; \
|
||||
if (skip >= 256) \
|
||||
return; \
|
||||
cl++; \
|
||||
} while (0)
|
||||
|
||||
void readFat(uint16_t *dest, int skip) {
|
||||
int cl = 0;
|
||||
skip = -skip;
|
||||
WRITE_ENT(0xfff0);
|
||||
WRITE_ENT(0xffff);
|
||||
for (ClusterData *c = firstCluster; c; c = c->cnext) {
|
||||
for (int i = 0; i < c->numclusters - 1; i++)
|
||||
WRITE_ENT(cl + 1);
|
||||
if (c->cnext && c->cnext->flags & F_CONT)
|
||||
WRITE_ENT(cl + 1);
|
||||
else
|
||||
WRITE_ENT(0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
// note that ptr might be unaligned
|
||||
const char *copyVFatName(const char *ptr, void *dest, int len) {
|
||||
uint8_t *dst = dest;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (ptr == NULL) {
|
||||
*dst++ = 0xff;
|
||||
*dst++ = 0xff;
|
||||
} else {
|
||||
*dst++ = *ptr;
|
||||
*dst++ = 0;
|
||||
if (*ptr)
|
||||
ptr++;
|
||||
else
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t fatChecksum(const char *name) {
|
||||
uint8_t sum = 0;
|
||||
for (int i = 0; i < 11; ++i)
|
||||
sum = ((sum & 1) << 7) + (sum >> 1) + *name++;
|
||||
return sum;
|
||||
}
|
||||
|
||||
void readDirData(uint8_t *dest, FsEntry *dirdata, int blkno) {
|
||||
DirEntry *d = (void *)dest;
|
||||
int idx = blkno * -16;
|
||||
for (FsEntry *e = dirdata; e; e = e->next) {
|
||||
if (idx >= 16)
|
||||
break;
|
||||
|
||||
// DBG("dir idx=%d %s", idx, e->vfatname);
|
||||
|
||||
for (int i = 0; i < e->numdirentries; ++i, ++idx) {
|
||||
if (0 <= idx && idx < 16) {
|
||||
if (i == e->numdirentries - 1) {
|
||||
memcpy(d->name, e->fatname, 11);
|
||||
d->attrs = e->attrs;
|
||||
d->size = e->size;
|
||||
d->startCluster = e->startCluster;
|
||||
timeToFat(e->mtime, &d->updateDate, &d->updateTime);
|
||||
timeToFat(e->ctime, &d->createDate, &d->createTime);
|
||||
} else {
|
||||
VFatEntry *f = (void *)d;
|
||||
int seq = e->numdirentries - i - 2;
|
||||
f->seqno = seq + 1; // they start at 1
|
||||
if (i == 0)
|
||||
f->seqno |= 0x40;
|
||||
f->attrs = 0x0F;
|
||||
f->type = 0x00;
|
||||
f->checksum = fatChecksum(e->fatname);
|
||||
f->startCluster = 0;
|
||||
|
||||
const char *ptr = e->vfatname + (13 * seq);
|
||||
ptr = copyVFatName(ptr, f->name0, 5);
|
||||
ptr = copyVFatName(ptr, f->name1, 6);
|
||||
ptr = copyVFatName(ptr, f->name2, 2);
|
||||
}
|
||||
d++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readBlock(uint8_t *dest, int blkno) {
|
||||
// DBG("readbl %d", blkno);
|
||||
int blkno0 = blkno;
|
||||
for (ClusterData *c = firstCluster; c; c = c->cnext) {
|
||||
// DBG("off=%d sz=%d", blkno, c->numclusters);
|
||||
if (blkno >= c->numclusters) {
|
||||
blkno -= c->numclusters;
|
||||
continue;
|
||||
}
|
||||
// DBG("readbl off=%d %p", blkno, c);
|
||||
if (c->dirdata) {
|
||||
readDirData(dest, c->dirdata, blkno);
|
||||
} else if (c->flags & F_TEXT) {
|
||||
strcpy((char *)dest, c->name);
|
||||
} else if (c->flags & F_UF2) {
|
||||
UF2_Block *bl = (void *)dest;
|
||||
|
||||
bl->magicStart0 = UF2_MAGIC_START0;
|
||||
bl->magicStart1 = UF2_MAGIC_START1;
|
||||
bl->magicEnd = UF2_MAGIC_END;
|
||||
bl->flags = UF2_FLAG_FILE;
|
||||
bl->blockNo = blkno0 - (c->myfile->startCluster - 2);
|
||||
bl->numBlocks = c->myfile->size / 512;
|
||||
bl->targetAddr = blkno * 256;
|
||||
bl->payloadSize = 256;
|
||||
bl->fileSize = c->st.st_size;
|
||||
|
||||
int fd = open(expandMap(c->name), O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
lseek(fd, bl->targetAddr, SEEK_SET);
|
||||
bl->payloadSize = read(fd, bl->data, 256);
|
||||
close(fd);
|
||||
} else {
|
||||
bl->payloadSize = -1;
|
||||
}
|
||||
|
||||
if (bl->payloadSize < 475 - strlen(c->name))
|
||||
strcpy((char *)bl->data + bl->payloadSize, c->name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void read_block(uint32_t block_no, uint8_t *data) {
|
||||
memset(data, 0, 512);
|
||||
uint32_t sectionIdx = block_no;
|
||||
|
||||
if (block_no == 0) {
|
||||
memcpy(data, &BootBlock, sizeof(BootBlock));
|
||||
data[510] = 0x55;
|
||||
data[511] = 0xaa;
|
||||
// logval("data[0]", data[0]);
|
||||
} else if (block_no < START_ROOTDIR) {
|
||||
sectionIdx -= START_FAT0;
|
||||
if (sectionIdx >= SECTORS_PER_FAT) // second copy of fat?
|
||||
sectionIdx -= SECTORS_PER_FAT;
|
||||
|
||||
readFat((void *)data, sectionIdx * 256);
|
||||
} else if (block_no < START_CLUSTERS) {
|
||||
sectionIdx -= START_ROOTDIR;
|
||||
readDirData(data, rootDir, sectionIdx);
|
||||
} else {
|
||||
sectionIdx -= START_CLUSTERS;
|
||||
readBlock(data, sectionIdx);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t numWritten;
|
||||
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
|
||||
} WriteState;
|
||||
|
||||
void restartProgram() {
|
||||
if (!rbfPath[0])
|
||||
exit(0);
|
||||
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;
|
||||
}
|
||||
|
||||
(void)block_no;
|
||||
|
||||
bl->data[475] = 0; // make sure we have NUL terminator
|
||||
char *fn0 = (char *)bl->data + bl->payloadSize;
|
||||
int namelen = 0;
|
||||
if (bl->payloadSize <= UF2_MAX_PAYLOAD) {
|
||||
namelen = strlen(fn0);
|
||||
}
|
||||
|
||||
if ((bl->flags & UF2_FLAG_FILE) && bl->fileSize <= UF2_MAX_FILESIZE &&
|
||||
bl->targetAddr < bl->fileSize && 1 <= namelen && namelen <= UF2_FILENAME_MAX) {
|
||||
|
||||
char *firstSL = strchr(fn0, '/');
|
||||
char *lastSL = strrchr(fn0, '/');
|
||||
if (!lastSL)
|
||||
lastSL = fn0;
|
||||
else
|
||||
lastSL++;
|
||||
int baseLen = strlen(lastSL);
|
||||
char fallback[strlen(dirMaps[0].fsName) + 1 + baseLen + 1];
|
||||
sprintf(fallback, "%s/%s", dirMaps[0].fsName, lastSL);
|
||||
char *fn = NULL;
|
||||
|
||||
if (firstSL && firstSL + 1 == lastSL)
|
||||
fn = expandMap(fn0);
|
||||
if (!fn)
|
||||
fn = fallback;
|
||||
|
||||
char *p = strrchr(fn, '/');
|
||||
*p = 0;
|
||||
mkdir(fn, 0777);
|
||||
*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", bl->payloadSize, bl->targetAddr, fn);
|
||||
write(fd, bl->data, bl->payloadSize);
|
||||
close(fd);
|
||||
|
||||
if (strlen(fn) > 4 && !strcmp(fn + strlen(fn) - 4, ".rbf")) {
|
||||
strcpy(rbfPath, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state && bl->numBlocks) {
|
||||
if (state->numBlocks != bl->numBlocks) {
|
||||
if (bl->numBlocks >= MAX_BLOCKS || state->numBlocks)
|
||||
state->numBlocks = 0xffffffff;
|
||||
else
|
||||
state->numBlocks = bl->numBlocks;
|
||||
}
|
||||
if (bl->blockNo < MAX_BLOCKS) {
|
||||
uint8_t mask = 1 << (bl->blockNo % 8);
|
||||
uint32_t pos = bl->blockNo / 8;
|
||||
if (!(state->writtenMask[pos] & mask)) {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO timeout for restart?
|
||||
}
|
||||
}
|
@ -1,231 +0,0 @@
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <linux/nbd.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#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
|
||||
|
||||
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);
|
||||
if (curr < 0)
|
||||
FAIL("read failed on fd:%d", fd);
|
||||
length -= curr;
|
||||
dst = (char *)dst + curr;
|
||||
}
|
||||
}
|
||||
|
||||
void writeAll(int fd, void *dst, uint32_t length) {
|
||||
while (length) {
|
||||
int curr = write(fd, dst, length);
|
||||
if (curr < 0)
|
||||
FAIL("write failed on fd:%d", fd);
|
||||
length -= curr;
|
||||
dst = (char *)dst + curr;
|
||||
}
|
||||
}
|
||||
|
||||
int nbd;
|
||||
int sock;
|
||||
int sockets[2];
|
||||
struct nbd_request request;
|
||||
struct nbd_reply reply;
|
||||
|
||||
void nbd_ioctl(unsigned id, int arg) {
|
||||
int err = ioctl(nbd, id, arg);
|
||||
if (err < 0)
|
||||
FAIL("ioctl(%ud) failed [%s]", id, strerror(errno));
|
||||
}
|
||||
|
||||
void startclient() {
|
||||
close(sockets[0]);
|
||||
nbd_ioctl(NBD_SET_SOCK, sockets[1]);
|
||||
nbd_ioctl(NBD_DO_IT, 0);
|
||||
nbd_ioctl(NBD_CLEAR_QUE, 0);
|
||||
nbd_ioctl(NBD_CLEAR_SOCK, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void handleread(int off, int len) {
|
||||
uint8_t buf[512];
|
||||
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);
|
||||
writeAll(sock, buf, 512);
|
||||
}
|
||||
}
|
||||
|
||||
void handlewrite(int off, int len) {
|
||||
uint8_t buf[512];
|
||||
LOG("write @%d len=%d", off, len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
readAll(sock, buf, 512);
|
||||
write_block(off + i, buf);
|
||||
}
|
||||
reply.error = 0;
|
||||
writeAll(sock, &reply, sizeof(struct nbd_reply));
|
||||
}
|
||||
|
||||
void setupFs();
|
||||
|
||||
void runNBD() {
|
||||
setupFs();
|
||||
|
||||
int err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
|
||||
assert(err >= 0);
|
||||
|
||||
nbd = open(dev_file, O_RDWR);
|
||||
assert(nbd >= 0);
|
||||
|
||||
nbd_ioctl(BLKFLSBUF, 0);
|
||||
nbd_ioctl(NBD_SET_BLKSIZE, 512);
|
||||
nbd_ioctl(NBD_SET_SIZE_BLOCKS, NUM_BLOCKS);
|
||||
nbd_ioctl(NBD_CLEAR_SOCK, 0);
|
||||
|
||||
if (!fork())
|
||||
startclient();
|
||||
|
||||
int fd = open(dev_file, O_RDONLY);
|
||||
assert(fd != -1);
|
||||
close(fd);
|
||||
|
||||
close(sockets[1]);
|
||||
sock = sockets[0];
|
||||
|
||||
reply.magic = htonl(NBD_REPLY_MAGIC);
|
||||
reply.error = htonl(0);
|
||||
|
||||
for (;;) {
|
||||
// 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) {
|
||||
FAIL("nbd read err %s", strerror(errno));
|
||||
}
|
||||
if (nread == 0)
|
||||
return;
|
||||
assert(nread == sizeof(request));
|
||||
memcpy(reply.handle, request.handle, sizeof(reply.handle));
|
||||
reply.error = htonl(0);
|
||||
|
||||
assert(request.magic == htonl(NBD_REQUEST_MAGIC));
|
||||
|
||||
uint32_t len = ntohl(request.len);
|
||||
assert((len & 511) == 0);
|
||||
len >>= 9;
|
||||
uint64_t from = ntohll(request.from);
|
||||
assert((from & 511) == 0);
|
||||
from >>= 9;
|
||||
|
||||
switch (ntohl(request.type)) {
|
||||
case NBD_CMD_READ:
|
||||
handleread(from, len);
|
||||
break;
|
||||
case NBD_CMD_WRITE:
|
||||
handlewrite(from, len);
|
||||
break;
|
||||
case NBD_CMD_DISC:
|
||||
return;
|
||||
default:
|
||||
FAIL("invalid cmd: %d", ntohl(request.type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enableMSD(int enabled) {
|
||||
#ifndef X86
|
||||
int fd = open("/sys/devices/platform/musb_hdrc/gadget/lun0/active", O_WRONLY);
|
||||
write(fd, enabled ? "1" : "0", 1);
|
||||
close(fd);
|
||||
#else
|
||||
LOG("fake enable MSD: %d", enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
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) {
|
||||
runNBD();
|
||||
return 0;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
enableMSD(1);
|
||||
|
||||
int wstatus = 0;
|
||||
waitpid(child, &wstatus, 0);
|
||||
enableMSD(0); // force "eject"
|
||||
|
||||
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
|
||||
LOG("abnormal child return, %d", child);
|
||||
sleep(5);
|
||||
} else {
|
||||
sleep(2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#ifndef UF2_H
|
||||
#define UF2_H 1
|
||||
|
||||
#include "uf2format.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef INDEX_URL
|
||||
#define INDEX_URL "https://www.pxt.io/"
|
||||
#endif
|
||||
|
||||
#define UF2_VERSION_BASE "v0.1.0"
|
||||
|
||||
// needs to be more than ~4200 and less than ~65000 (to force FAT16)
|
||||
#define NUM_FAT_BLOCKS 65000
|
||||
|
||||
#define UF2_VERSION UF2_VERSION_BASE " F"
|
||||
|
||||
//! Static block size for all memories
|
||||
#define UDI_MSC_BLOCK_SIZE 512L
|
||||
|
||||
void read_block(uint32_t block_no, uint8_t *data);
|
||||
|
||||
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) }
|
||||
|
||||
extern const char infoUf2File[];
|
||||
|
||||
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,48 +0,0 @@
|
||||
#ifndef UF2FORMAT_H
|
||||
#define UF2FORMAT_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// All entries are little endian.
|
||||
|
||||
// if you increase that, you will also need to update the linker script file
|
||||
#define APP_START_ADDRESS 0x00002000
|
||||
|
||||
#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"
|
||||
#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected
|
||||
#define UF2_MAGIC_END 0x0AB16F30UL // Ditto
|
||||
|
||||
// If set, the block is "comment" and should not be flashed to the device
|
||||
#define UF2_FLAG_NOFLASH 0x00000001
|
||||
#define UF2_FLAG_FILE 0x00001000
|
||||
#define UF2_FILENAME_MAX 150
|
||||
#define UF2_MAX_PAYLOAD (476 - 10) // leaving some space for filename
|
||||
// for this bootloader
|
||||
#define UF2_MAX_FILESIZE (64 * 1024 * 1024)
|
||||
|
||||
typedef struct {
|
||||
// 32 byte header
|
||||
uint32_t magicStart0;
|
||||
uint32_t magicStart1;
|
||||
uint32_t flags;
|
||||
uint32_t targetAddr;
|
||||
uint32_t payloadSize;
|
||||
uint32_t blockNo;
|
||||
uint32_t numBlocks;
|
||||
uint32_t fileSize;
|
||||
|
||||
// raw data, followed by filename (NUL-terminated) at payloadSize
|
||||
uint8_t data[476];
|
||||
|
||||
// store magic also at the end to limit damage from partial block reads
|
||||
uint32_t magicEnd;
|
||||
} UF2_Block;
|
||||
|
||||
static inline bool is_uf2_block(void *data) {
|
||||
UF2_Block *bl = (UF2_Block *)data;
|
||||
return bl->magicStart0 == UF2_MAGIC_START0 && bl->magicStart1 == UF2_MAGIC_START1 &&
|
||||
bl->magicEnd == UF2_MAGIC_END;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,106 +0,0 @@
|
||||
#ifndef UF2_HID_H
|
||||
#define UF2_HID_H 1
|
||||
|
||||
#define HF2_CMD_BININFO 0x0001
|
||||
// no arguments
|
||||
#define HF2_MODE_BOOTLOADER 0x01
|
||||
#define HF2_MODE_USERSPACE 0x02
|
||||
struct HF2_BININFO_Result {
|
||||
uint32_t mode;
|
||||
uint32_t flash_page_size;
|
||||
uint32_t flash_num_pages;
|
||||
uint32_t max_message_size;
|
||||
};
|
||||
|
||||
#define HF2_CMD_INFO 0x0002
|
||||
// no arguments
|
||||
// results is utf8 character array
|
||||
|
||||
#define HF2_CMD_RESET_INTO_APP 0x0003
|
||||
// no arguments, no result
|
||||
|
||||
#define HF2_CMD_RESET_INTO_BOOTLOADER 0x0004
|
||||
// no arguments, no result
|
||||
|
||||
#define HF2_CMD_START_FLASH 0x0005
|
||||
// no arguments, no result
|
||||
|
||||
#define HF2_CMD_WRITE_FLASH_PAGE 0x0006
|
||||
struct HF2_WRITE_FLASH_PAGE_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t data[0];
|
||||
};
|
||||
// no result
|
||||
|
||||
#define HF2_CMD_CHKSUM_PAGES 0x0007
|
||||
struct HF2_CHKSUM_PAGES_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t num_pages;
|
||||
};
|
||||
struct HF2_CHKSUM_PAGES_Result {
|
||||
uint16_t chksums[0 /* num_pages */];
|
||||
};
|
||||
|
||||
#define HF2_CMD_READ_WORDS 0x0008
|
||||
struct HF2_READ_WORDS_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t num_words;
|
||||
};
|
||||
struct HF2_READ_WORDS_Result {
|
||||
uint32_t words[0 /* num_words */];
|
||||
};
|
||||
|
||||
#define HF2_CMD_WRITE_WORDS 0x0009
|
||||
struct HF2_WRITE_WORDS_Command {
|
||||
uint32_t target_addr;
|
||||
uint32_t num_words;
|
||||
uint32_t words[0 /* num_words */];
|
||||
};
|
||||
// no result
|
||||
|
||||
#define HF2_CMD_DMESG 0x0010
|
||||
// no arguments
|
||||
// results is utf8 character array
|
||||
|
||||
typedef struct {
|
||||
uint32_t command_id;
|
||||
uint16_t tag;
|
||||
uint8_t reserved0;
|
||||
uint8_t reserved1;
|
||||
|
||||
union {
|
||||
struct HF2_WRITE_FLASH_PAGE_Command write_flash_page;
|
||||
struct HF2_WRITE_WORDS_Command write_words;
|
||||
struct HF2_READ_WORDS_Command read_words;
|
||||
struct HF2_CHKSUM_PAGES_Command chksum_pages;
|
||||
};
|
||||
} HF2_Command;
|
||||
|
||||
typedef struct {
|
||||
uint16_t tag;
|
||||
union {
|
||||
struct {
|
||||
uint8_t status;
|
||||
uint8_t status_info;
|
||||
};
|
||||
uint16_t status16;
|
||||
};
|
||||
union {
|
||||
struct HF2_BININFO_Result bininfo;
|
||||
uint8_t data8[0];
|
||||
uint16_t data16[0];
|
||||
uint32_t data32[0];
|
||||
};
|
||||
} HF2_Response;
|
||||
|
||||
#define HF2_FLAG_SERIAL_OUT 0x80
|
||||
#define HF2_FLAG_SERIAL_ERR 0xC0
|
||||
#define HF2_FLAG_CMDPKT_LAST 0x40
|
||||
#define HF2_FLAG_CMDPKT_BODY 0x00
|
||||
#define HF2_FLAG_MASK 0xC0
|
||||
#define HF2_SIZE_MASK 63
|
||||
|
||||
#define HF2_STATUS_OK 0x00
|
||||
#define HF2_STATUS_INVALID_CMD 0x01
|
||||
|
||||
#endif
|
1
docfiles/robotsmeta.html
Normal file
1
docfiles/robotsmeta.html
Normal file
@ -0,0 +1 @@
|
||||
<meta name="robots" content="noindex">
|
@ -3,9 +3,3 @@
|
||||
## Reference #reference
|
||||
|
||||
* [Reference](/reference)
|
||||
* [input](/reference/input)
|
||||
* [light](/reference/light)
|
||||
* [music](/reference/music)
|
||||
* [pins](/reference/pins)
|
||||
* [control](/reference/control)
|
||||
* [serial](/reference/serial)
|
||||
|
@ -1,19 +1,3 @@
|
||||
# Reference
|
||||
|
||||
```namespaces
|
||||
input.onGesture(Gesture.Shake, () => {})
|
||||
light.showRing('red red red red red red red red red red')
|
||||
music.playTone(0, 0)
|
||||
pins.pulseDuration()
|
||||
control.runInBackground(() => {})
|
||||
serial.writeLine("");
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
[blocks](/blocks), [JavaScript](/javascript), [input](/reference/input), [light](/reference/light), [music](/reference/music),
|
||||
[control](/reference/control), [pins](/reference/pins), [serial](/reference/serial)
|
||||
|
||||
```package
|
||||
circuit-playground
|
||||
```
|
||||
TODO
|
BIN
docs/static/hero.png
vendored
Normal file
BIN
docs/static/hero.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
74
docs/static/lego-logo.svg
vendored
Normal file
74
docs/static/lego-logo.svg
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="141.73"
|
||||
height="141.731"
|
||||
viewBox="0 0 141.73 141.73101"
|
||||
enable-background="new 0 0 265.365 141.732"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="lego-logo.svg"><metadata
|
||||
id="metadata26"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs24" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1199"
|
||||
inkscape:window-height="604"
|
||||
id="namedview22"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="1.6520876"
|
||||
inkscape:cx="101.03204"
|
||||
inkscape:cy="98.819336"
|
||||
inkscape:window-x="372"
|
||||
inkscape:window-y="149"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g6" /><g
|
||||
id="product_logo" /><g
|
||||
id="guides" /><g
|
||||
id="LEGO_LOGO_SMALL_RGB"><g
|
||||
id="g6"><path
|
||||
d="m 0.961,0.948 0,139.839 139.84,0 0,-139.839 -139.84,0 z"
|
||||
id="path8"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff" /><path
|
||||
d="m 0.961,0.948 0,139.839 139.84,0 0,-139.839 -139.84,0 z m 130.536,58.127 c -0.23,4.356 -1.617,9.786 -2.839,13.414 -4.917,14.609 -10.618,23.666 -23.821,23.666 -3.887,0 -10.783,-1.031 -13.324,-7.947 l -0.602,-1.641 -1.082,1.371 C 85.7,93.168 79.564,96.186 72.998,96.217 67.96,96.24 63.912,94.553 61.293,91.334 l -0.718,-0.883 -0.765,0.844 c -2.797,3.088 -7.668,4.859 -13.364,4.859 -4.473,0 -8.335,-1.521 -10.876,-4.277 l -0.692,-0.752 -0.72,0.727 c -2.825,2.852 -7.276,4.289 -12.873,4.158 -6.79,-0.162 -10.924,-3.951 -11.058,-10.141 -0.205,-9.543 9.031,-29.622 12.854,-35.727 2.482,-4.078 5.895,-6.055 10.438,-6.055 3.092,0 5.207,0.646 6.463,1.977 1.144,1.211 1.37,2.232 1.472,4.688 l 0.131,3.175 1.676,-2.7 c 4.054,-6.532 10.773,-7.434 17.43,-7.434 4.628,0 8.667,1.702 10.289,4.336 l 0.599,0.971 0.866,-0.737 c 3.431,-2.916 8.271,-4.521 13.629,-4.521 5.849,0 10.099,1.454 12.634,4.322 0.576,0.651 0.957,1.106 1.486,2.219 l 0.651,1.366 0.977,-1.155 c 3.712,-4.39 8.779,-6.615 15.067,-6.615 4.98,0 8.761,1.324 11.235,3.935 3.104,3.271 3.547,7.875 3.373,11.161 z"
|
||||
id="path10"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f6ec36" /><path
|
||||
d="m 0.961,0.948 0,139.839 139.84,0 0,-139.839 -139.84,0 z M 135.435,64.44 c -0.633,5.089 -4.072,14.518 -5.899,18.286 -4.903,10.102 -11.453,17.863 -24.074,17.863 -6.742,0 -12.288,-2.15 -15.531,-6.283 -4.749,4.162 -10.627,6.342 -16.956,6.342 -4.876,0 -9.185,-1.408 -12.471,-4.012 -3.626,2.555 -8.52,3.98 -13.943,3.98 -4.53,0 -8.606,-1.244 -11.796,-3.543 -3.529,2.342 -8.154,3.506 -13.583,3.377 C 12.149,100.237 5.912,94.507 5.733,86.188 5.497,75.137 14.803,54.911 19.189,47.907 c 3.282,-5.392 8.292,-8.293 14.431,-8.293 6.663,0 9.078,1.903 10.267,4.326 5.141,-4.366 11.956,-4.617 16.808,-4.617 5.356,0 8.717,1.422 11.575,3.697 3.948,-2.368 8.477,-3.599 13.871,-3.599 6.897,0 12.021,1.604 15.595,5.137 4.168,-3.469 9.388,-5.05 15.23,-5.05 7.725,0 12.808,2.786 15.793,6.94 4.203,5.859 3.451,11.757 2.676,17.992 z"
|
||||
id="path12"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#d01012" /><path
|
||||
d="m 0,0 0,141.731 141.73,0 L 141.73,0 0,0 Z m 139.781,1.952 0,137.832 -137.83,0 0,-137.832 137.83,0 z"
|
||||
id="path14"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 134.752,42.53 0,-0.965 0.655,0 c 0.479,0 0.728,0.168 0.728,0.479 0,0.247 -0.16,0.486 -0.647,0.486 l -0.736,0 z m 2.351,2.002 -0.408,-0.708 c -0.354,-0.619 -0.452,-0.717 -0.755,-0.823 l 0,-0.019 c 0.596,-0.07 0.95,-0.453 0.95,-0.983 0,-0.56 -0.354,-0.984 -1.109,-0.984 l -1.754,0 0,3.519 0.727,0 0,-1.441 0.133,0 c 0.311,0 0.435,0.035 0.576,0.176 0.142,0.144 0.354,0.443 0.479,0.69 l 0.284,0.575 0.877,-0.002 0,0 z m -1.731,-4.497 c 1.51,0 2.737,1.218 2.737,2.726 0,1.508 -1.229,2.731 -2.737,2.731 -1.506,0 -2.72,-1.225 -2.72,-2.731 0,-1.506 1.214,-2.726 2.72,-2.726 z m 0,-0.67 c -1.877,0 -3.392,1.516 -3.392,3.396 0,1.879 1.515,3.394 3.392,3.394 1.883,0 3.397,-1.515 3.397,-3.394 0.002,-1.882 -1.514,-3.396 -3.397,-3.396 z"
|
||||
id="path16"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 116.889,43.002 c -7.325,0 -12.386,2.904 -15.812,6.961 -0.579,-1.214 -1.019,-1.746 -1.638,-2.447 -2.805,-3.17 -7.313,-4.649 -13.364,-4.649 -5.912,0 -10.841,1.846 -14.263,4.754 -1.777,-2.89 -6.013,-4.803 -11.121,-4.803 -6.674,0 -13.946,0.944 -18.261,7.896 -0.104,-2.503 -0.33,-3.828 -1.737,-5.317 -1.71,-1.81 -4.477,-2.282 -7.173,-2.282 -4.912,0 -8.605,2.146 -11.266,6.515 -3.859,6.163 -13.212,26.441 -13.001,36.263 0.137,6.344 4.393,10.916 12.01,11.096 5.952,0.143 10.62,-1.449 13.59,-4.447 2.665,2.896 6.731,4.594 11.596,4.594 5.417,0 10.868,-1.627 14.088,-5.182 2.712,3.332 6.979,5.271 12.468,5.244 7.175,-0.035 13.477,-3.438 17.593,-8.652 2.259,6.148 7.985,8.59 14.241,8.59 13.709,0 19.729,-9.428 24.748,-24.332 1.13,-3.357 2.639,-8.963 2.889,-13.672 0.413,-7.839 -2.903,-16.13 -15.587,-16.13 z M 25.672,80.477 c 7.093,-1.232 8.876,1.332 8.653,3.707 -0.669,7.109 -7.191,8.699 -12.854,8.566 -4.107,-0.1 -7.8,-1.98 -7.903,-6.748 -0.18,-8.342 8.328,-27.641 12.333,-34.038 1.85,-3.037 4.104,-4.539 7.698,-4.539 3.406,0 4.25,1.749 4.2,3.844 -0.134,5.589 -9.164,22.574 -12.127,29.208 z M 48.77,73.925 c -0.469,1.27 -1.357,3.93 -2.076,6.75 2.328,-0.582 4.074,-0.986 7.065,-0.914 3.408,0.084 5.586,1.496 5.586,4.314 0,6.832 -7.551,8.838 -12.789,8.838 -5.751,0 -10.803,-3.275 -10.803,-9.564 0,-7.373 3.997,-18.553 7.748,-26.001 4.606,-9.146 9.312,-10.362 17.419,-10.362 3.562,0 7.667,1.524 7.667,4.888 0,4.662 -3.95,6.44 -7.866,6.665 -1.672,0.096 -4.246,0.188 -5.786,0.079 0,0 -1.303,1.985 -2.688,5.523 7.252,-1.021 10.327,0.625 9.103,4.82 -1.657,5.667 -6.567,6.04 -12.58,4.964 z M 84.438,56.293 c -1.961,0 -3.244,1.242 -4.198,2.583 -2.102,2.952 -6.656,14.781 -7.365,19.64 -0.486,3.328 0.951,4.006 2.522,4.006 2.52,0 5.345,-2.666 6.309,-7.064 0,0 -4.797,-0.117 -3.475,-4.371 1.285,-4.128 3.723,-5.022 7.764,-5.188 7.961,-0.325 7.175,5.553 6.538,8.688 -2.069,10.18 -9.314,18.355 -19.562,18.355 -7.016,0 -11.371,-3.881 -11.371,-11.035 0,-5.098 2.529,-13.101 4.534,-17.784 4.267,-9.968 8.742,-16.944 20.143,-16.944 6.84,0 12.235,2.458 11.444,8.866 -0.58,4.703 -2.934,7.465 -7.21,7.799 -1.196,0.093 -6.089,-0.031 -4.466,-4.66 0.565,-1.619 0.799,-2.891 -1.607,-2.891 z m 43.057,8.413 c -1.205,6.002 -3.916,13.101 -6.859,18.392 -4.801,8.633 -10.633,9.842 -15.723,9.781 -5.093,-0.061 -10.83,-1.941 -10.874,-9.795 -0.031,-5.639 2.401,-13.598 4.466,-18.815 3.599,-9.458 7.277,-17.17 18.904,-17.031 13.559,0.161 11.141,12.219 10.086,17.468 z M 115.993,56.49 c -1.164,-0.016 -2.18,0.212 -3.093,1.62 -2.051,2.657 -8.047,19.042 -7.941,22.31 0.038,1.174 0.687,2.201 2.133,2.201 1.659,0.002 2.581,-1.145 3.396,-2.529 1.887,-3.193 7.193,-17.676 7.339,-21.297 0.043,-1.055 -0.133,-2.284 -1.834,-2.305 z"
|
||||
id="path18"
|
||||
inkscape:connector-curvature="0" /></g></g></svg>
|
After Width: | Height: | Size: 7.7 KiB |
BIN
docs/static/lego_education_logo.png
vendored
Normal file
BIN
docs/static/lego_education_logo.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
@ -28,13 +28,33 @@ namespace pxt.editor {
|
||||
|
||||
let initPromise: Promise<Ev3Wrapper>
|
||||
function initAsync() {
|
||||
if (!initPromise)
|
||||
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
|
||||
}
|
||||
|
||||
@ -116,13 +136,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);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,53 @@
|
||||
{
|
||||
"Array": "Add, remove, and replace items in lists.\n\nAdd, remove, and replace items in lists.",
|
||||
"Array.filter": "Return 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": "Get the value at a particular index",
|
||||
"Array.get|param|index": "the zero-based position in the list of the item, eg: 0",
|
||||
"Array.indexOf": "Return 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": "Get or set the length of an array. This number is one more than the index of the last element the array.",
|
||||
"Array.map": "Call a defined callback function on each element of an array, and return an array containing 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": "Remove the last element from an array and return it.",
|
||||
"Array.push": "Append a new element to an array.",
|
||||
"Array.reduce": "Call 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": "Remove the element at a certain index.",
|
||||
"Array.removeElement": "Remove the first occurence of an object. Returns true if removed.",
|
||||
"Array.reverse": "Reverse the elements in an array. The first array element becomes the last, and the last array element becomes the first.",
|
||||
"Array.set": "Store a value at a particular index",
|
||||
"Array.set|param|index": "the zero-based position in the list to store the value, eg: 0",
|
||||
"Array.shift": "Remove the first element from an array and return it. This method changes the length of the array.",
|
||||
"Array.slice": "Return 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": "Sort the elements of an array in place and returns the array. The sort is not necessarily stable.",
|
||||
"Array.splice": "Remove 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": "Add one element to the beginning of an array and return the new length of the array.",
|
||||
"Boolean.toString": "Returns a string representation of an object.",
|
||||
"Buffer.fill": "Fill (a fragment) of the buffer with given value.",
|
||||
"Buffer.getNumber": "Read a number in specified format from the buffer.",
|
||||
"Buffer.length": "Returns the length of a Buffer object.",
|
||||
"Buffer.rotate": "Rotate buffer left in place.\n\n\n\nstart. eg: -1",
|
||||
"Buffer.rotate|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus",
|
||||
"Buffer.rotate|param|offset": "number of bytes to shift; use negative value to shift right",
|
||||
"Buffer.rotate|param|start": "start offset in buffer. Default is 0.",
|
||||
"Buffer.setNumber": "Write a number in specified format in the buffer.",
|
||||
"Buffer.shift": "Shift buffer left in place, with zero padding.\n\n\n\nstart. eg: -1",
|
||||
"Buffer.shift|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus",
|
||||
"Buffer.shift|param|offset": "number of bytes to shift; use negative value to shift right",
|
||||
"Buffer.shift|param|start": "start offset in buffer. Default is 0.",
|
||||
"Buffer.slice": "Return a copy of a fragment of a buffer.",
|
||||
"Buffer.toHex": "Convert a buffer to its hexadecimal representation.",
|
||||
"Buffer.write": "Write contents of `src` at `dstOffset` in current buffer.",
|
||||
"Math": "More complex operations with numbers.",
|
||||
"Math.abs": "Returns the absolute value of a number (the value without regard to whether it is positive or negative).\nFor example, the absolute value of -5 is the same as the absolute value of 5.",
|
||||
"Math.abs|param|x": "A numeric expression for which the absolute value is needed.",
|
||||
"Math.acos": "Returns the arccosine (in radians) of a number",
|
||||
@ -58,22 +107,26 @@
|
||||
"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.charAt": "Returns the character at the specified index.",
|
||||
"Number.toString": "Returns a string representation of a number.",
|
||||
"String": "Combine, split, and search text strings.\n\nCombine, split, and search text strings.",
|
||||
"String.charAt": "Return the character at the specified index.",
|
||||
"String.charAt|param|index": "The zero-based index of the desired character.",
|
||||
"String.charCodeAt": "Returns the Unicode value of the character at the specified location.",
|
||||
"String.charCodeAt": "Return the Unicode value of the character at the specified location.",
|
||||
"String.charCodeAt|param|index": "The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.",
|
||||
"String.compare": "Determines whether relative order of two strings (in ASCII encoding).",
|
||||
"String.compare": "See how the order of characters in two strings is different (in ASCII encoding).",
|
||||
"String.compare|param|that": "String to compare to target string",
|
||||
"String.concat": "Returns a string that contains the concatenation of two or more strings.",
|
||||
"String.concat|param|other": "The string to append to the end of the string.",
|
||||
"String.fromCharCode": "Make a string from the given ASCII character code.",
|
||||
"String.isEmpty": "Returns a value indicating if the string is empty",
|
||||
"String.length": "Returns the length of a String object.",
|
||||
"String.substr": "Return 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|start": "first character index; can be negative from counting from the end, eg:0",
|
||||
"control": "Program controls and events.",
|
||||
"control.assert": "Display specified error code and stop the program.",
|
||||
"control.AnimationQueue.cancel": "Cancels the current running animation and clears the queue",
|
||||
"control.AnimationQueue.runUntilDone": "Runs 'render' in a loop until it returns false or the 'stop' function is called",
|
||||
"control.assert": "Display an error code and stop the program when the assertion is `false`.",
|
||||
"control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.",
|
||||
"control.millis": "Gets the number of milliseconds elapsed since power on.",
|
||||
"control.onEvent": "Run code when a registered event happens.",
|
||||
@ -85,9 +138,13 @@
|
||||
"control.waitForEvent": "Blocks the calling thread until the specified event is raised.",
|
||||
"control.waitMicros": "Block the current fiber for the given microseconds",
|
||||
"control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4",
|
||||
"hex": "Tagged hex literal converter",
|
||||
"loops.forever": "Repeats the code forever in the background. On each iteration, allows other codes to run.",
|
||||
"loops.pause": "Pause for the specified time in milliseconds",
|
||||
"loops.pause|param|ms": "how long to pause for, eg: 100, 200, 500, 1000, 2000",
|
||||
"loops.timePicker": "Get the time field editor",
|
||||
"loops.timePicker|param|ms": "time duration in milliseconds, eg: 500, 1000",
|
||||
"parseInt": "Convert a string to an integer.",
|
||||
"serial": "Reading and writing data over a serial connection.",
|
||||
"serial.writeBuffer": "Send a buffer across the serial connection.",
|
||||
"serial.writeLine": "Write a line of text to the serial port.",
|
||||
|
@ -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",
|
||||
@ -9,6 +19,7 @@
|
||||
"String.length|block": "length of %VALUE",
|
||||
"String.substr|block": "substring of %this=text|from %start|of length %length",
|
||||
"String|block": "String",
|
||||
"control.assert|block": "assert %cond|with value %code",
|
||||
"control.deviceSerialNumber|block": "device serial number",
|
||||
"control.millis|block": "millis (ms)",
|
||||
"control.onEvent|block": "on event|from %src|with value %value",
|
||||
@ -19,17 +30,25 @@
|
||||
"control.waitMicros|block": "wait (µs)%micros",
|
||||
"control|block": "control",
|
||||
"loops.forever|block": "forever",
|
||||
"loops.pause|block": "pause (ms) %pause",
|
||||
"loops.pause|block": "pause %ms=timePicker|ms",
|
||||
"loops.timePicker|block": "%ms",
|
||||
"loops|block": "loops",
|
||||
"parseInt|block": "parse to integer %text",
|
||||
"serial.writeBuffer|block": "serial|write buffer %buffer",
|
||||
"serial.writeLine|block": "serial|write line %text",
|
||||
"serial.writeNumber|block": "serial|write number %value",
|
||||
"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}Boolean": "Boolean",
|
||||
"{id:category}Buffer": "Buffer",
|
||||
"{id:category}Control": "Control",
|
||||
"{id:category}Helpers": "Helpers",
|
||||
"{id:category}Loops": "Loops",
|
||||
"{id:category}Math": "Math",
|
||||
"{id:category}Number": "Number",
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:category}String": "String",
|
||||
"{id:category}Text": "Text"
|
||||
|
11
libs/base/shims.d.ts
vendored
11
libs/base/shims.d.ts
vendored
@ -70,7 +70,7 @@ declare namespace loops {
|
||||
* Repeats the code forever in the background. On each iteration, allows other codes to run.
|
||||
* @param body code to execute
|
||||
*/
|
||||
//% help=loops/forever weight=100 blockGap=8
|
||||
//% help=loops/forever weight=100 afterOnStart=true
|
||||
//% blockId=forever block="forever" blockAllowMultiple=1 shim=loops::forever
|
||||
function forever(a: () => void): void;
|
||||
|
||||
@ -79,7 +79,7 @@ declare namespace loops {
|
||||
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
|
||||
*/
|
||||
//% help=loops/pause weight=99
|
||||
//% async block="pause (ms) %pause"
|
||||
//% async block="pause %ms=timePicker|ms"
|
||||
//% blockId=device_pause shim=loops::pause
|
||||
function pause(ms: int32): void;
|
||||
}
|
||||
@ -120,7 +120,7 @@ declare namespace control {
|
||||
/**
|
||||
* Run other code in the background.
|
||||
*/
|
||||
//% help=control/run-in-background blockAllowMultiple=1
|
||||
//% help=control/run-in-background blockAllowMultiple=1 afterOnStart=true
|
||||
//% blockId="control_run_in_background" block="run in background" blockGap=8 shim=control::runInBackground
|
||||
function runInBackground(a: () => void): void;
|
||||
|
||||
@ -134,7 +134,8 @@ declare namespace control {
|
||||
/**
|
||||
* 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
|
||||
//% blockId="control_device_serial_number" block="device serial number" weight=9
|
||||
//% help=control/device-serial-number shim=control::deviceSerialNumber
|
||||
function deviceSerialNumber(): int32;
|
||||
}
|
||||
declare namespace serial {
|
||||
@ -150,7 +151,7 @@ declare namespace serial {
|
||||
/**
|
||||
* Send a buffer across the serial connection.
|
||||
*/
|
||||
//% help=serial/write-buffer advanced=true weight=6
|
||||
//% help=serial/write-buffer weight=6
|
||||
//% blockId=serial_writebuffer block="serial|write buffer %buffer" shim=serial::writeBuffer
|
||||
function writeBuffer(buffer: Buffer): void;
|
||||
}
|
||||
|
@ -1,4 +1,15 @@
|
||||
{
|
||||
"ButtonEvent": "User interaction on buttons",
|
||||
"Draw": "Drawing modes",
|
||||
"LightsPattern": "Patterns for lights under the buttons.",
|
||||
"MMap.getNumber": "Read a number in specified format from the buffer.",
|
||||
"MMap.ioctl": "Perform ioctl(2) on the underlaying file",
|
||||
"MMap.length": "Returns the length of a Buffer object.",
|
||||
"MMap.read": "Perform read(2) on the underlaying file",
|
||||
"MMap.setNumber": "Write a number in specified format in the buffer.",
|
||||
"MMap.slice": "Read a range of bytes into a buffer.",
|
||||
"MMap.write": "Perform write(2) on the underlaying file",
|
||||
"TouchSensorEvent": "Touch sensor interactions",
|
||||
"control": "Program controls and events.",
|
||||
"control.allocateNotifyEvent": "Allocates the next user notification event",
|
||||
"control.deviceFirmwareVersion": "Determine the version of system software currently running.",
|
||||
@ -7,23 +18,56 @@
|
||||
"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|value": "Component specific code indicating the cause of the event.",
|
||||
"input": "Respond to and read data from buttons and sensors.",
|
||||
"input.Button": "Generic button class, for device buttons and sensors.",
|
||||
"input.buttonDown": "Down button.",
|
||||
"input.buttonEnter": "Enter button.",
|
||||
"input.buttonLeft": "Left button.",
|
||||
"input.buttonRight": "Right button.",
|
||||
"input.buttonUp": "Up button.",
|
||||
"input.Button.isPressed": "Check if button is currently pressed or not.",
|
||||
"input.Button.onEvent": "Do something when a button or sensor is clicked, double clicked, etc...",
|
||||
"input.Button.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
||||
"input.ColorSensor.ambientLight": "Get current ambient light value from the color sensor.",
|
||||
"input.ColorSensor.color": "Get the current color from the color sensor.",
|
||||
"input.ColorSensor.reflectedLight": "Get current reflected light value from the color sensor.",
|
||||
"input.GyroSensor.angle": "Get the current angle from the gyroscope.",
|
||||
"input.GyroSensor.rate": "Get the current rotation rate from the gyroscope.",
|
||||
"input.IrSensor.distance": "Get the distance measured by the infrared sensor.",
|
||||
"input.IrSensor.remoteCommand": "Get the remote commandreceived the infrared sensor.",
|
||||
"input.TouchSensor.isTouched": "Check if touch sensor is touched.",
|
||||
"input.TouchSensor.onEvent": "Do something when a touch sensor is touched...",
|
||||
"input.TouchSensor.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.UltraSonicSensor.distance": "Gets the distance from the sonar in millimeters",
|
||||
"input.buttonDown": "Down button on the EV3 Brick.",
|
||||
"input.buttonEnter": "Enter button on the EV3 Brick.",
|
||||
"input.buttonLeft": "Left button on the EV3 Brick.",
|
||||
"input.buttonRight": "Right button on the EV3 Brick.",
|
||||
"input.buttonUp": "Up button on the EV3 Brick.",
|
||||
"input.remoteBottomLeft": "Remote bottom-left button.",
|
||||
"input.remoteBottomRight": "Remote bottom-right button.",
|
||||
"input.remoteCenter": "Remote beacon (center) button.",
|
||||
"input.remoteTopLeft": "Remote top-left button.",
|
||||
"input.remoteTopRight": "Remote top-right button.",
|
||||
"output.Motor.off": "Power off the motor.",
|
||||
"output.Motor.on": "Power on the motor.",
|
||||
"output.Motor.onForTime": "Power on the motor for a specified number of milliseconds.",
|
||||
"output.Motor.onForTime|param|brake": "whether or not to use the brake",
|
||||
"output.Motor.onForTime|param|ms": "the number of milliseconds to turn the motor on, eg: 500",
|
||||
"output.Motor.onForTime|param|power": "the motor power level from ``-100`` to ``100``, eg: 50",
|
||||
"output.Motor.on|param|power": "the motor power level from ``-100`` to ``100``, eg: 50",
|
||||
"output.Motor.setPower": "Sets the motor power level from ``-100`` to ``100``.",
|
||||
"output.Motor.setPower|param|power": "the desired speed to use. eg: 50",
|
||||
"output.Motor.speed": "Gets motor actual speed.",
|
||||
"output.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"output.createBuffer|param|size": "number of bytes in the buffer",
|
||||
"output.setLights": "Set lights.",
|
||||
"output.pattern": "Pattern block.",
|
||||
"output.pattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||
"output.setStatusLight": "Set lights.",
|
||||
"output.setStatusLight|param|pattern": "the lights pattern to use.",
|
||||
"screen.clear": "Clear screen and reset font to normal.",
|
||||
"screen.doubleIcon": "Double size of an icon.",
|
||||
"screen.drawIcon": "Draw an icon on the screen.",
|
||||
"screen.print": "Show text on the screen.",
|
||||
"screen.print|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||
"screen.print|param|x": "the starting position's x coordinate, eg: 0",
|
||||
"screen.print|param|y": "the starting position's x coordinate, eg: 0",
|
||||
"serial": "Reading and writing data over a serial connection.",
|
||||
"serial.writeDmesg": "Send DMESG debug buffer over serial."
|
||||
}
|
@ -1,28 +1,93 @@
|
||||
{
|
||||
"ButtonEvent.Click|block": "click",
|
||||
"ButtonEvent.Down|block": "down",
|
||||
"ButtonEvent.LongClick|block": "long click",
|
||||
"ButtonEvent.Up|block": "up",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value value",
|
||||
"LightsPattern.GreenFlash|block": "Flashing Green",
|
||||
"LightsPattern.GreenPulse|block": "Pulsing Green",
|
||||
"LightsPattern.Green|block": "Green",
|
||||
"LightsPattern.Off|block": "Off",
|
||||
"LightsPattern.OrangeFlash|block": "Flashing Orange",
|
||||
"LightsPattern.OrangePulse|block": "Pulsing Orange",
|
||||
"LightsPattern.Orange|block": "Orange",
|
||||
"LightsPattern.RedFlash|block": "Flashing Red",
|
||||
"LightsPattern.RedPulse|block": "Pulsing Red",
|
||||
"LightsPattern.Red|block": "Red",
|
||||
"Output.ALL|block": "All",
|
||||
"Output.A|block": "A",
|
||||
"Output.B|block": "B",
|
||||
"Output.C|block": "C",
|
||||
"Output.D|block": "D",
|
||||
"TouchSensorEvent.Bumped|block": "bumped",
|
||||
"TouchSensorEvent.Released|block": "released",
|
||||
"TouchSensorEvent.Touched|block": "touched",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||
"control|block": "control",
|
||||
"input.buttonDown|block": "button down",
|
||||
"input.buttonEnter|block": "button enter",
|
||||
"input.buttonLeft|block": "button left",
|
||||
"input.buttonRight|block": "button right",
|
||||
"input.buttonUp|block": "button up",
|
||||
"input.Button.isPressed|block": "%button|is pressed",
|
||||
"input.Button.onEvent|block": "on %button|%event",
|
||||
"input.Button.wasPressed|block": "%button|was pressed",
|
||||
"input.ColorSensor.ambientLight|block": "%color| ambient light",
|
||||
"input.ColorSensor.color|block": "%color| color",
|
||||
"input.ColorSensor.reflectedLight|block": "%color| reflected light",
|
||||
"input.GyroSensor.angle|block": "%sensor|angle",
|
||||
"input.GyroSensor.rate|block": "%sensor|rotation rate",
|
||||
"input.IrSensor.distance|block": "%infrared|distance",
|
||||
"input.IrSensor.remoteCommand|block": "%infrared|remote command",
|
||||
"input.TouchSensor.isTouched|block": "%sensor|is touched",
|
||||
"input.TouchSensor.onEvent|block": "on %sensor|%event",
|
||||
"input.UltraSonicSensor.distance|block": "%sensor|distance",
|
||||
"input.buttonDown|block": "brick button down",
|
||||
"input.buttonEnter|block": "brick button enter",
|
||||
"input.buttonLeft|block": "brick button left",
|
||||
"input.buttonRight|block": "brick button right",
|
||||
"input.buttonUp|block": "brick button up",
|
||||
"input.color1|block": "color sensor 1",
|
||||
"input.color2|block": "color sensor 2",
|
||||
"input.color3|block": "color sensor 3",
|
||||
"input.color4|block": "color sensor 4",
|
||||
"input.gyro1|block": "gyro sensor 1",
|
||||
"input.gyro2|block": "gyro sensor 2",
|
||||
"input.gyro3|block": "gyro sensor 3",
|
||||
"input.gyro4|block": "gyro sensor 4",
|
||||
"input.remoteBottomLeft|block": "remote bottom-left",
|
||||
"input.remoteBottomRight|block": "remote bottom-right",
|
||||
"input.remoteCenter|block": "remote center",
|
||||
"input.remoteTopLeft|block": "remote top-left",
|
||||
"input.remoteTopRight|block": "remote top-right",
|
||||
"input.touchSensor1|block": "touch sensor 1",
|
||||
"input.touchSensor2|block": "touch sensor 2",
|
||||
"input.touchSensor3|block": "touch sensor 3",
|
||||
"input.touchSensor4|block": "touch sensor 4",
|
||||
"input.ultrasonic1|block": "ultrasonic sensor 1",
|
||||
"input.ultrasonic2|block": "ultrasonic sensor 2",
|
||||
"input.ultrasonic3|block": "ultrasonic sensor 3",
|
||||
"input.ultrasonic4|block": "ultrasonic sensor 4",
|
||||
"input|block": "input",
|
||||
"output.setLights|block": "set lights %pattern",
|
||||
"output.Motor.off|block": "%motor|OFF then brake %brake",
|
||||
"output.Motor.onForTime|block": "%motor|ON at power %power|for %ms=timePicker|ms then brake %brake",
|
||||
"output.Motor.on|block": "%motor|ON at power %power",
|
||||
"output.Motor.setPower|block": "%motor|set power to %speed",
|
||||
"output.Motor.speed|block": "%motor|speed",
|
||||
"output.motorA|block": "motor A",
|
||||
"output.motorB|block": "motor B",
|
||||
"output.motorC|block": "motor C",
|
||||
"output.motorD|block": "motor D",
|
||||
"output.pattern|block": "%pattern",
|
||||
"output.setStatusLight|block": "set status light %pattern=led_pattern",
|
||||
"output|block": "output",
|
||||
"screen.print|block": "print %text| at x: %x| y: %y",
|
||||
"screen|block": "screen",
|
||||
"serial|block": "serial",
|
||||
"{id:category}Control": "Control",
|
||||
"{id:category}Input": "Input",
|
||||
"{id:category}MMap": "MMap",
|
||||
"{id:category}Output": "Output",
|
||||
"{id:category}Screen": "Screen",
|
||||
"{id:category}Serial": "Serial"
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:group}Brick": "Brick",
|
||||
"{id:group}Color Sensor": "Color Sensor",
|
||||
"{id:group}Gyro Sensor": "Gyro Sensor",
|
||||
"{id:group}Infrared Sensor": "Infrared Sensor",
|
||||
"{id:group}Motors": "Motors",
|
||||
"{id:group}Touch Sensor": "Touch Sensor",
|
||||
"{id:group}Ultrasonic Sensor": "Ultrasonic Sensor"
|
||||
}
|
@ -3,15 +3,35 @@
|
||||
* Patterns for lights under the buttons.
|
||||
*/
|
||||
const enum LightsPattern {
|
||||
//% block=Off enumval=0
|
||||
//% blockIdentity=output.pattern
|
||||
Off = 0,
|
||||
//% block=Green enumval=1
|
||||
//% blockIdentity=output.pattern
|
||||
Green = 1,
|
||||
//% block=Red enumval=2
|
||||
//% blockIdentity=output.pattern
|
||||
Red = 2,
|
||||
//% block=Orange enumval=3
|
||||
//% blockIdentity=output.pattern
|
||||
Orange = 3,
|
||||
//% block="Flashing Green" enumval=4
|
||||
//% blockIdentity=output.pattern
|
||||
GreenFlash = 4,
|
||||
//% block="Flashing Red" enumval=5
|
||||
//% blockIdentity=output.pattern
|
||||
RedFlash = 5,
|
||||
//% block="Flashing Orange" enumval=6
|
||||
//% blockIdentity=output.pattern
|
||||
OrangeFlash = 6,
|
||||
//% block="Pulsing Green" enumval=7
|
||||
//% blockIdentity=output.pattern
|
||||
GreenPulse = 7,
|
||||
//% block="Pulsing Red" enumval=8
|
||||
//% blockIdentity=output.pattern
|
||||
RedPulse = 8,
|
||||
//% block="Pulsing Orange" enumval=9
|
||||
//% blockIdentity=output.pattern
|
||||
OrangePulse = 9,
|
||||
}
|
||||
|
||||
@ -21,8 +41,6 @@ const enum LightsPattern {
|
||||
const enum ButtonEvent {
|
||||
//% block="click"
|
||||
Click = 1,
|
||||
//% block="long click"
|
||||
LongClick = 2,
|
||||
//% block="up"
|
||||
Up = 3,
|
||||
//% block="down"
|
||||
@ -56,7 +74,8 @@ namespace input {
|
||||
} else {
|
||||
control.raiseEvent(this._id, ButtonEvent.Up)
|
||||
let delta = control.millis() - this.downTime
|
||||
control.raiseEvent(this._id, delta > 500 ? ButtonEvent.LongClick : ButtonEvent.Click)
|
||||
control.raiseEvent(this._id, ButtonEvent.Click)
|
||||
//control.raiseEvent(this._id, delta > 500 ? ButtonEvent.LongClick : ButtonEvent.Click)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,15 +83,13 @@ namespace input {
|
||||
* Check if button is currently pressed or not.
|
||||
* @param button the button to query the request
|
||||
*/
|
||||
//% help=input/button/is-pressed weight=79
|
||||
//% help=input/button/is-pressed
|
||||
//% block="%button|is pressed"
|
||||
//% blockId=buttonIsPressed
|
||||
//% blockGap=8
|
||||
//% parts="buttonpair"
|
||||
//% parts="brick"
|
||||
//% blockNamespace=input
|
||||
//% button.fieldEditor="gridpicker"
|
||||
//% button.fieldOptions.width=220
|
||||
//% button.fieldOptions.columns=3
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Brick"
|
||||
isPressed() {
|
||||
return this._isPressed
|
||||
}
|
||||
@ -81,14 +98,13 @@ namespace input {
|
||||
* See if the button was pressed again since the last time you checked.
|
||||
* @param button the button to query the request
|
||||
*/
|
||||
//% help=input/button/was-pressed weight=78
|
||||
//% help=input/button/was-pressed
|
||||
//% block="%button|was pressed"
|
||||
//% blockId=buttonWasPressed
|
||||
//% parts="buttonpair" blockGap=8
|
||||
//% blockNamespace=input advanced=true
|
||||
//% button.fieldEditor="gridpicker"
|
||||
//% button.fieldOptions.width=220
|
||||
//% button.fieldOptions.columns=3
|
||||
//% parts="brick"
|
||||
//% blockNamespace=input
|
||||
//% weight=80 blockGap=8
|
||||
//% group="Brick"
|
||||
wasPressed() {
|
||||
const r = this._wasPressed
|
||||
this._wasPressed = false
|
||||
@ -101,13 +117,12 @@ namespace input {
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
*/
|
||||
//% help=input/button/on-event weight=99 blockGap=8
|
||||
//% help=input/button/on-event
|
||||
//% blockId=buttonEvent block="on %button|%event"
|
||||
//% parts="buttonpair"
|
||||
//% parts="brick"
|
||||
//% blockNamespace=input
|
||||
//% button.fieldEditor="gridpicker"
|
||||
//% button.fieldOptions.width=220
|
||||
//% button.fieldOptions.columns=3
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Brick"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
control.onEvent(this._id, ev, body)
|
||||
}
|
||||
@ -161,35 +176,36 @@ namespace input {
|
||||
|
||||
initBtns() // always ON as it handles ESCAPE button
|
||||
|
||||
|
||||
/**
|
||||
* Left button.
|
||||
* Enter button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button left" weight=95 fixedInstance
|
||||
//% whenUsed block="brick button enter" weight=95 fixedInstance
|
||||
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
|
||||
|
||||
/**
|
||||
* Left button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="brick button left" weight=95 fixedInstance
|
||||
export const buttonLeft: Button = new DevButton(DAL.BUTTON_ID_LEFT)
|
||||
|
||||
/**
|
||||
* Right button.
|
||||
* Right button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button right" weight=94 fixedInstance
|
||||
//% whenUsed block="brick button right" weight=94 fixedInstance
|
||||
export const buttonRight: Button = new DevButton(DAL.BUTTON_ID_RIGHT)
|
||||
|
||||
/**
|
||||
* Up button.
|
||||
* Up button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button up" weight=95 fixedInstance
|
||||
//% whenUsed block="brick button up" weight=95 fixedInstance
|
||||
export const buttonUp: Button = new DevButton(DAL.BUTTON_ID_UP)
|
||||
|
||||
/**
|
||||
* Down button.
|
||||
* Down button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="button down" weight=95 fixedInstance
|
||||
//% whenUsed block="brick button down" weight=95 fixedInstance
|
||||
export const buttonDown: Button = new DevButton(DAL.BUTTON_ID_DOWN)
|
||||
|
||||
/**
|
||||
* Enter button.
|
||||
*/
|
||||
//% whenUsed block="button enter" weight=95 fixedInstance
|
||||
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
|
||||
}
|
||||
|
||||
|
||||
@ -215,9 +231,11 @@ namespace output {
|
||||
|
||||
/**
|
||||
* Set lights.
|
||||
* @param pattern the lights pattern to use.
|
||||
*/
|
||||
//% blockId=setLights block="set lights %pattern"
|
||||
export function setLights(pattern: LightsPattern): void {
|
||||
//% blockId=setLights block="set status light %pattern=led_pattern"
|
||||
//% weight=100 group="Brick"
|
||||
export function setStatusLight(pattern: number): void {
|
||||
if (currPattern === pattern)
|
||||
return
|
||||
currPattern = pattern
|
||||
@ -225,4 +243,16 @@ namespace output {
|
||||
cmd[0] = pattern + 48
|
||||
input.internal.getBtnsMM().write(cmd)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pattern block.
|
||||
* @param pattern the lights pattern to use. eg: LightsPattern.Green
|
||||
*/
|
||||
//% blockId=led_pattern block="%pattern"
|
||||
//% shim=TD_ID colorSecondary="#6e9a36"
|
||||
//% blockHidden=true useEnumVal=1 pattern.fieldOptions.decompileLiterals=1
|
||||
export function pattern(pattern: LightsPattern): number {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,10 @@ const enum ColorSensorColor {
|
||||
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class ColorSensor extends internal.UartSensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
@ -34,22 +35,64 @@ namespace input {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
getAmbientLight() {
|
||||
/**
|
||||
* Get current ambient light value from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
*/
|
||||
//% help=input/color/ambient-light
|
||||
//% block="%color| ambient light"
|
||||
//% blockId=colorGetAmbient
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
ambientLight() {
|
||||
this.setMode(ColorSensorMode.Ambient)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
getReflectedLight() {
|
||||
/**
|
||||
* Get current reflected light value from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
*/
|
||||
//% help=input/color/refelected-light
|
||||
//% block="%color| reflected light"
|
||||
//% blockId=colorGetReflected
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=64 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
reflectedLight(): number {
|
||||
this.setMode(ColorSensorMode.Reflect)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
getColor(): ColorSensorColor {
|
||||
/**
|
||||
* Get the current color from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
*/
|
||||
//% help=input/color/color
|
||||
//% block="%color| color"
|
||||
//% blockId=colorGetColor
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=66 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
color(): ColorSensorColor {
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const color: ColorSensor = new ColorSensor()
|
||||
//% whenUsed block="color sensor 3" weight=95 fixedInstance
|
||||
export const color3: ColorSensor = new ColorSensor(3)
|
||||
|
||||
//% whenUsed block="color sensor 1" weight=95 fixedInstance
|
||||
export const color1: ColorSensor = new ColorSensor(1)
|
||||
|
||||
//% whenUsed block="color sensor 2" weight=95 fixedInstance
|
||||
export const color2: ColorSensor = new ColorSensor(2)
|
||||
|
||||
//% whenUsed block="color sensor 4" weight=95 fixedInstance
|
||||
export const color4: ColorSensor = new ColorSensor(4)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace control {
|
||||
* @param mode optional definition of how the event should be processed after construction.
|
||||
*/
|
||||
//% weight=21 blockGap=12 blockId="control_raise_event"
|
||||
//% block="raise event|from %src|with value value" blockExternalInputs=1
|
||||
//% block="raise event|from %src|with value %value" blockExternalInputs=1
|
||||
void raiseEvent(int src, int value) {
|
||||
pxt::raiseEvent(src, value);
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ const enum GyroSensorMode {
|
||||
}
|
||||
|
||||
namespace input {
|
||||
//% fixedInstances
|
||||
export class GyroSensor extends internal.UartSensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
@ -18,17 +19,48 @@ namespace input {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
getAngle() {
|
||||
/**
|
||||
* Get the current angle from the gyroscope.
|
||||
* @param sensor the gyroscope to query the request
|
||||
*/
|
||||
//% help=input/gyro/angle
|
||||
//% block="%sensor|angle"
|
||||
//% blockId=gyroGetAngle
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
angle() {
|
||||
this.setMode(GyroSensorMode.Angle)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
}
|
||||
|
||||
getRate() {
|
||||
/**
|
||||
* Get the current rotation rate from the gyroscope.
|
||||
* @param sensor the gyroscope to query the request
|
||||
*/
|
||||
//% help=input/gyro/rate
|
||||
//% block="%sensor|rotation rate"
|
||||
//% blockId=gyroGetRate
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
rate() {
|
||||
this.setMode(GyroSensorMode.Rate)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const gyro: GyroSensor = new GyroSensor()
|
||||
//% fixedInstance whenUsed block="gyro sensor 2"
|
||||
export const gyro2: GyroSensor = new GyroSensor(2)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro sensor 1"
|
||||
export const gyro1: GyroSensor = new GyroSensor(1)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro sensor 3"
|
||||
export const gyro3: GyroSensor = new GyroSensor(3)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro sensor 4"
|
||||
export const gyro4: GyroSensor = new GyroSensor(4)
|
||||
}
|
||||
|
@ -27,30 +27,27 @@ namespace input.internal {
|
||||
let analogMM: MMap
|
||||
let uartMM: MMap
|
||||
let devcon: Buffer
|
||||
let sensors: SensorInfo[]
|
||||
let autoSensors: Sensor[]
|
||||
let sensorInfos: SensorInfo[]
|
||||
|
||||
class SensorInfo {
|
||||
port: number
|
||||
sensor: Sensor
|
||||
sensors: Sensor[]
|
||||
connType: number
|
||||
devType: number
|
||||
manual: boolean
|
||||
|
||||
constructor(p: number) {
|
||||
this.port = p
|
||||
this.connType = DAL.CONN_NONE
|
||||
this.devType = DAL.DEVICE_TYPE_NONE
|
||||
this.sensor = null
|
||||
this.manual = false
|
||||
this.sensors = []
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (sensors) return
|
||||
sensors = []
|
||||
for (let i = 0; i < DAL.NUM_INPUTS; ++i) sensors.push(new SensorInfo(i))
|
||||
autoSensors = []
|
||||
if (sensorInfos) return
|
||||
sensorInfos = []
|
||||
for (let i = 0; i < DAL.NUM_INPUTS; ++i) sensorInfos.push(new SensorInfo(i))
|
||||
devcon = output.createBuffer(DevConOff.Size)
|
||||
|
||||
analogMM = control.mmap("/dev/lms_analog", AnalogOff.Size, 0)
|
||||
@ -64,7 +61,7 @@ namespace input.internal {
|
||||
loops.pause(500)
|
||||
})
|
||||
|
||||
for (let info_ of sensors) {
|
||||
for (let info_ of sensorInfos) {
|
||||
let info = info_
|
||||
unsafePollForChanges(50, () => {
|
||||
if (info.sensor) return info.sensor._query()
|
||||
@ -90,7 +87,7 @@ namespace input.internal {
|
||||
let conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
|
||||
let numChanged = 0
|
||||
|
||||
for (let info of sensors) {
|
||||
for (let info of sensorInfos) {
|
||||
let newConn = conns[info.port]
|
||||
if (newConn == info.connType)
|
||||
continue
|
||||
@ -117,77 +114,42 @@ namespace input.internal {
|
||||
if (numChanged == 0)
|
||||
return
|
||||
|
||||
let autos = sensors.filter(s => !s.manual)
|
||||
|
||||
// first free up disconnected sensors
|
||||
for (let info of autos) {
|
||||
if (info.sensor && info.devType == DAL.DEVICE_TYPE_NONE)
|
||||
info.sensor._setPort(0)
|
||||
}
|
||||
|
||||
for (let info of autos) {
|
||||
if (!info.sensor && info.devType != DAL.DEVICE_TYPE_NONE) {
|
||||
let found = false
|
||||
for (let s of autoSensors) {
|
||||
if (s.getPort() == 0 && s._deviceType() == info.devType) {
|
||||
s._setPort(info.port + 1)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
for (let si of sensorInfos) {
|
||||
if (si.sensor && si.sensor._deviceType() != si.devType) {
|
||||
si.sensor = null
|
||||
}
|
||||
if (si.devType != DAL.DEVICE_TYPE_NONE) {
|
||||
si.sensor = si.sensors.filter(s => s._deviceType() == si.devType)[0] || null
|
||||
if (si.sensor == null) {
|
||||
control.dmesg(`sensor not found for type=${si.devType} at ${si.port}`)
|
||||
} else {
|
||||
control.dmesg(`sensor connected type=${si.devType} at ${si.port}`)
|
||||
si.sensor._activated()
|
||||
}
|
||||
if (!found)
|
||||
control.dmesg(`sensor not found for type=${info.devType} at ${info.port}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Sensor extends control.Component {
|
||||
protected port: number
|
||||
protected port: number // this is 0-based
|
||||
|
||||
constructor() {
|
||||
constructor(port_: number) {
|
||||
super()
|
||||
if (!(1 <= port_ && port_ <= DAL.NUM_INPUTS))
|
||||
control.panic(120)
|
||||
this.port = port_ - 1
|
||||
init()
|
||||
this.port = -1
|
||||
let tp = this._deviceType()
|
||||
if (autoSensors.filter(s => s._deviceType() == tp).length == 0) {
|
||||
autoSensors.push(this)
|
||||
}
|
||||
}
|
||||
|
||||
// 0 - disable, 1-4 port number
|
||||
_setPort(port: number, manual = false) {
|
||||
port = Math.clamp(0, 4, port | 0) - 1;
|
||||
if (port == this.port) return
|
||||
this.port = port
|
||||
control.dmesg(`sensor set port ${port} on devtype=${this._deviceType()}`)
|
||||
for (let i = 0; i < sensors.length; ++i) {
|
||||
if (i != this.port && sensors[i].sensor == this) {
|
||||
sensors[i].sensor = null
|
||||
sensors[i].manual = false
|
||||
}
|
||||
}
|
||||
if (this.port >= 0) {
|
||||
let prev = sensors[this.port].sensor
|
||||
if (prev && prev != this)
|
||||
prev._setPort(0)
|
||||
sensors[this.port].sensor = this
|
||||
sensors[this.port].manual = manual
|
||||
}
|
||||
this._portUpdated()
|
||||
}
|
||||
|
||||
protected _portUpdated() { }
|
||||
|
||||
setPort(port: number) {
|
||||
this._setPort(port, true)
|
||||
}
|
||||
_activated() { }
|
||||
|
||||
// 1-based
|
||||
getPort() {
|
||||
return this.port + 1
|
||||
}
|
||||
|
||||
isManual() {
|
||||
return this.port >= 0 && sensors[this.port].manual
|
||||
isActive() {
|
||||
return sensorInfos[this.port].sensor == this
|
||||
}
|
||||
|
||||
_query() {
|
||||
@ -203,12 +165,12 @@ namespace input.internal {
|
||||
}
|
||||
|
||||
export class AnalogSensor extends Sensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_readPin6() {
|
||||
if (this.port < 0) return 0
|
||||
if (!this.isActive()) return 0
|
||||
return analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.InPin6 + 2 * this.port)
|
||||
}
|
||||
}
|
||||
@ -216,32 +178,26 @@ namespace input.internal {
|
||||
|
||||
|
||||
export class UartSensor extends Sensor {
|
||||
protected mode: number
|
||||
protected realmode: number
|
||||
protected mode: number // the mode user asked for
|
||||
protected realmode: number // the mode the hardware is in
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.mode = 0
|
||||
this.realmode = -1
|
||||
}
|
||||
|
||||
protected _portUpdated() {
|
||||
this.realmode = -1
|
||||
if (this.port >= 0) {
|
||||
if (this.isManual()) {
|
||||
uartReset(this.port)
|
||||
} else {
|
||||
this.realmode = 0
|
||||
}
|
||||
this._setMode(this.mode)
|
||||
}
|
||||
_activated() {
|
||||
this.realmode = 0
|
||||
// uartReset(this.port) // TODO is it ever needed?
|
||||
this._setMode(this.mode)
|
||||
}
|
||||
|
||||
protected _setMode(m: number) {
|
||||
//control.dmesg(`_setMode p=${this.port} m: ${this.realmode} -> ${m}`)
|
||||
let v = m | 0
|
||||
this.mode = v
|
||||
if (this.port < 0) return
|
||||
if (!this.isActive()) return
|
||||
if (this.realmode != this.mode) {
|
||||
this.realmode = v
|
||||
setUartMode(this.port, v)
|
||||
@ -249,10 +205,12 @@ namespace input.internal {
|
||||
}
|
||||
|
||||
getBytes(): Buffer {
|
||||
return getUartBytes(this.port)
|
||||
return getUartBytes(this.isActive() ? this.port : -1)
|
||||
}
|
||||
|
||||
getNumber(fmt: NumberFormat, off: number) {
|
||||
if (!this.isActive())
|
||||
return 0
|
||||
return getUartNumber(fmt, off, this.port)
|
||||
}
|
||||
}
|
||||
|
105
libs/core/ir.ts
105
libs/core/ir.ts
@ -40,29 +40,46 @@ namespace input {
|
||||
}
|
||||
}
|
||||
|
||||
export class IrSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel
|
||||
private buttons: Button[];
|
||||
let buttons: Button[]
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.channel = IrRemoteChannel.Ch0
|
||||
this.buttons = []
|
||||
// otherwise button events won't work
|
||||
this.mode = IrSensorMode.RemoteControl
|
||||
function create(ir: IrSensor) {
|
||||
// it's created by referencing it
|
||||
}
|
||||
|
||||
export function irButton(id: IrRemoteButton) {
|
||||
if (buttons == null) {
|
||||
buttons = []
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
this.buttons.push(new Button())
|
||||
buttons.push(new Button())
|
||||
}
|
||||
|
||||
// make sure sensors are up
|
||||
create(ir1)
|
||||
create(ir2)
|
||||
create(ir3)
|
||||
create(ir4)
|
||||
}
|
||||
|
||||
button(id: IrRemoteButton) {
|
||||
let num = -1
|
||||
while (id) {
|
||||
id >>= 1;
|
||||
num++;
|
||||
}
|
||||
num = Math.clamp(0, this.buttons.length - 1, num)
|
||||
return this.buttons[num]
|
||||
let num = -1
|
||||
while (id) {
|
||||
id >>= 1;
|
||||
num++;
|
||||
}
|
||||
num = Math.clamp(0, buttons.length - 1, num)
|
||||
return buttons[num]
|
||||
}
|
||||
|
||||
//% fixedInstance
|
||||
export class IrSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.channel = IrRemoteChannel.Ch0
|
||||
irButton(0) // make sure buttons array is initalized
|
||||
|
||||
// and set the mode, as otherwise button events won't work
|
||||
this.mode = IrSensorMode.RemoteControl
|
||||
}
|
||||
|
||||
_query() {
|
||||
@ -72,9 +89,9 @@ namespace input {
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
for (let i = 0; i < this.buttons.length; ++i) {
|
||||
for (let i = 0; i < buttons.length; ++i) {
|
||||
let v = !!(curr & (1 << i))
|
||||
this.buttons[i].update(v)
|
||||
buttons[i].update(v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,16 +109,39 @@ namespace input {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
getDistance() {
|
||||
/**
|
||||
* Get the distance measured by the infrared sensor.
|
||||
* @param ir the infrared sensor
|
||||
*/
|
||||
//% help=input/infrared/distance
|
||||
//% block="%infrared|distance"
|
||||
//% blockId=infraredGetDistance
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
distance() {
|
||||
this.setMode(IrSensorMode.Proximity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
getRemoteCommand() {
|
||||
/**
|
||||
* Get the remote commandreceived the infrared sensor.
|
||||
* @param ir the infrared sensor
|
||||
*/
|
||||
//% help=input/infrared/remote-command
|
||||
//% block="%infrared|remote command"
|
||||
//% blockId=infraredGetRemoteCommand
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
remoteCommand() {
|
||||
this.setMode(IrSensorMode.RemoteControl)
|
||||
return this.getNumber(NumberFormat.UInt8LE, this.channel)
|
||||
}
|
||||
|
||||
// TODO
|
||||
getDirectionAndDistance() {
|
||||
this.setMode(IrSensorMode.Seek)
|
||||
return this.getNumber(NumberFormat.UInt16LE, this.channel * 2)
|
||||
@ -109,35 +149,44 @@ namespace input {
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const ir: IrSensor = new IrSensor()
|
||||
export const ir1: IrSensor = new IrSensor(1)
|
||||
|
||||
//% whenUsed
|
||||
export const ir2: IrSensor = new IrSensor(2)
|
||||
|
||||
//% whenUsed
|
||||
export const ir3: IrSensor = new IrSensor(3)
|
||||
|
||||
//% whenUsed
|
||||
export const ir4: IrSensor = new IrSensor(4)
|
||||
|
||||
/**
|
||||
* Remote top-left button.
|
||||
*/
|
||||
//% whenUsed block="remote top-left" weight=95 fixedInstance
|
||||
export const remoteTopLeft = ir.button(IrRemoteButton.TopLeft)
|
||||
export const remoteTopLeft = irButton(IrRemoteButton.TopLeft)
|
||||
|
||||
/**
|
||||
* Remote top-right button.
|
||||
*/
|
||||
//% whenUsed block="remote top-right" weight=95 fixedInstance
|
||||
export const remoteTopRight = ir.button(IrRemoteButton.TopRight)
|
||||
export const remoteTopRight = irButton(IrRemoteButton.TopRight)
|
||||
|
||||
/**
|
||||
* Remote bottom-left button.
|
||||
*/
|
||||
//% whenUsed block="remote bottom-left" weight=95 fixedInstance
|
||||
export const remoteBottomLeft = ir.button(IrRemoteButton.BottomLeft)
|
||||
export const remoteBottomLeft = irButton(IrRemoteButton.BottomLeft)
|
||||
|
||||
/**
|
||||
* Remote bottom-right button.
|
||||
*/
|
||||
//% whenUsed block="remote bottom-right" weight=95 fixedInstance
|
||||
export const remoteBottomRight = ir.button(IrRemoteButton.BottomRight)
|
||||
export const remoteBottomRight = irButton(IrRemoteButton.BottomRight)
|
||||
|
||||
/**
|
||||
* Remote beacon (center) button.
|
||||
*/
|
||||
//% whenUsed block="remote center" weight=95 fixedInstance
|
||||
export const remoteCenter = ir.button(IrRemoteButton.CenterBeacon)
|
||||
export const remoteCenter = irButton(IrRemoteButton.CenterBeacon)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
//% color="#B4009E" weight=98 icon="\uf192"
|
||||
//% groups='["Touch Sensor", "Gyro Sensor", "Color Sensor", "Ultrasonic Sensor", "Infrared Sensor", "Remote", "Brick"]'
|
||||
namespace input {
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
enum Output {
|
||||
//% block="A"
|
||||
A = 0x01,
|
||||
//% block="B"
|
||||
B = 0x02,
|
||||
//% block="C"
|
||||
C = 0x04,
|
||||
//% block="D"
|
||||
D = 0x08,
|
||||
//% block="All"
|
||||
ALL = 0x0f
|
||||
}
|
||||
|
||||
@ -29,71 +34,186 @@ namespace output {
|
||||
pwmMM = control.mmap("/dev/lms_pwm", 0, 0)
|
||||
if (!pwmMM) control.fail("no PWM file")
|
||||
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
||||
|
||||
stop(Output.ALL)
|
||||
|
||||
resetMotors()
|
||||
|
||||
let buf = output.createBuffer(1)
|
||||
buf[0] = DAL.opProgramStart
|
||||
writePWM(buf)
|
||||
}
|
||||
|
||||
|
||||
function writePWM(buf: Buffer): void {
|
||||
init()
|
||||
pwmMM.write(buf)
|
||||
}
|
||||
|
||||
function readPWM(buf: Buffer): void {
|
||||
init()
|
||||
pwmMM.read(buf);
|
||||
}
|
||||
|
||||
function mkCmd(out: Output, cmd: number, addSize: number) {
|
||||
let b = createBuffer(2 + addSize)
|
||||
const b = createBuffer(2 + addSize)
|
||||
b.setNumber(NumberFormat.UInt8LE, 0, cmd)
|
||||
b.setNumber(NumberFormat.UInt8LE, 1, out)
|
||||
return b
|
||||
}
|
||||
|
||||
export function stop(out: Output, useBreak = false) {
|
||||
let b = mkCmd(out, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, useBreak ? 1 : 0)
|
||||
writePWM(b)
|
||||
function resetMotors() {
|
||||
reset(Output.ALL)
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class Motor extends control.Component {
|
||||
port: Output;
|
||||
constructor(port: Output) {
|
||||
super();
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Power off the motor.
|
||||
* @param motor the motor to turn off
|
||||
*/
|
||||
//% blockId=outputMotorOf block="%motor|OFF then brake %brake"
|
||||
//% brake.fieldEditor=toggleonoff
|
||||
//% weight=100 group="Motors" blockGap=8
|
||||
off(brake = false) {
|
||||
const b = mkCmd(this.port, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, brake ? 1 : 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Power on the motor.
|
||||
* @param motor the motor to turn on
|
||||
* @param power the motor power level from ``-100`` to ``100``, eg: 50
|
||||
*/
|
||||
//% blockId=outputMotorOn block="%motor|ON at power %power"
|
||||
//% power.min=-100 power.max=100
|
||||
//% weight=99 group="Motors" blockGap=8
|
||||
on(power: number = 50) {
|
||||
this.setPower(power);
|
||||
const b = mkCmd(this.port, DAL.opOutputStart, 0)
|
||||
writePWM(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Power on the motor for a specified number of milliseconds.
|
||||
* @param motor the motor to turn on
|
||||
* @param power the motor power level from ``-100`` to ``100``, eg: 50
|
||||
* @param ms the number of milliseconds to turn the motor on, eg: 500
|
||||
* @param brake whether or not to use the brake
|
||||
*/
|
||||
//% blockId=outputMotorOnForTime block="%motor|ON at power %power|for %ms=timePicker|ms then brake %brake"
|
||||
//% power.min=-100 power.max=100
|
||||
//% brake.fieldEditor=toggleonoff
|
||||
//% weight=98 group="Motors" blockGap=8
|
||||
onForTime(power: number, ms: number, brake = false) {
|
||||
step(this.port, {
|
||||
power,
|
||||
step1: 0,
|
||||
step2: ms,
|
||||
step3: 0,
|
||||
useSteps: false,
|
||||
useBrake: brake
|
||||
})
|
||||
loops.pause(ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the motor power level from ``-100`` to ``100``.
|
||||
* @param motor the output connection that the motor is connected to
|
||||
* @param power the desired speed to use. eg: 50
|
||||
*/
|
||||
//% blockId=motorSetPower block="%motor|set power to %speed"
|
||||
//% weight=60 group="Motors"
|
||||
//% speed.min=-100 speed.max=100
|
||||
setPower(power: number) {
|
||||
const b = mkCmd(this.port, DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, power))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor actual speed.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorSpeed block="%motor|speed"
|
||||
//% weight=50 group="Motors" blockGap=8
|
||||
speed() {
|
||||
return getMotorData(this.port).actualSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
export function start(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputStart, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
//% whenUsed fixedInstance block="motor B"
|
||||
export const motorB = new Motor(Output.B);
|
||||
|
||||
export function reset(out: Output) {
|
||||
//% whenUsed fixedInstance block="motor C"
|
||||
export const motorC = new Motor(Output.C);
|
||||
|
||||
//% whenUsed fixedInstance block="motor A"
|
||||
export const motorA = new Motor(Output.A);
|
||||
|
||||
//% whenUsed fixedInstance block="motor D"
|
||||
export const motorD = new Motor(Output.D);
|
||||
|
||||
function reset(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export function setSpeed(out: Output, speed: number) {
|
||||
let b = mkCmd(out, DAL.opOutputSpeed, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, speed))
|
||||
function clearCount(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputClearCount, 0)
|
||||
writePWM(b)
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (out & (1 << i)) {
|
||||
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setPower(out: Output, power: number) {
|
||||
let b = mkCmd(out, DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, power))
|
||||
writePWM(b)
|
||||
function outOffset(out: Output) {
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (out & (1 << i))
|
||||
return i * MotorDataOff.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
export function setPolarity(out: Output, polarity: number) {
|
||||
interface MotorData {
|
||||
actualSpeed: number; // -100..+100
|
||||
tachoCount: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
// only a single output at a time
|
||||
function getMotorData(out: Output): MotorData {
|
||||
let buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
||||
return {
|
||||
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
||||
tachoCount: buf.getNumber(NumberFormat.Int32LE, MotorDataOff.TachoCounts),
|
||||
count: buf.getNumber(NumberFormat.Int32LE, MotorDataOff.TachoSensor),
|
||||
}
|
||||
}
|
||||
|
||||
function setPolarity(out: Output, polarity: number) {
|
||||
let b = mkCmd(out, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-1, 1, polarity))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export interface StepOptions {
|
||||
interface StepOptions {
|
||||
power?: number;
|
||||
speed?: number; // either speed or power has to be present
|
||||
step1: number;
|
||||
step2: number;
|
||||
step3: number;
|
||||
useSteps?: boolean; // otherwise use milliseconds
|
||||
useBreak?: boolean;
|
||||
useBrake?: boolean;
|
||||
}
|
||||
|
||||
export function step(out: Output, opts: StepOptions) {
|
||||
function step(out: Output, opts: StepOptions) {
|
||||
let op = opts.useSteps ? DAL.opOutputStepSpeed : DAL.opOutputTimeSpeed
|
||||
let speed = opts.speed
|
||||
if (speed == null) {
|
||||
@ -110,7 +230,7 @@ namespace output {
|
||||
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 0, opts.step1)
|
||||
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 1, opts.step2)
|
||||
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 2, opts.step3)
|
||||
b.setNumber(NumberFormat.Int8LE, 4 + 4 * 3, opts.useBreak ? 1 : 0)
|
||||
b.setNumber(NumberFormat.Int8LE, 4 + 4 * 3, opts.useBrake ? 1 : 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
|
@ -84,8 +84,18 @@ namespace screen {
|
||||
if (0 <= x && x < DAL.LCD_WIDTH && 0 <= y && y < DAL.LCD_HEIGHT)
|
||||
_setPixel(x, y, mode)
|
||||
}
|
||||
|
||||
|
||||
export function drawText(x: number, y: number, text: string, mode = Draw.Normal) {
|
||||
/**
|
||||
* Show text on the screen.
|
||||
* @param text the text to print on the screen, eg: "Hello world"
|
||||
* @param x the starting position's x coordinate, eg: 0
|
||||
* @param y the starting position's x coordinate, eg: 0
|
||||
*/
|
||||
//% blockId=screen_print block="print %text| at x: %x| y: %y"
|
||||
//% weight=99 group="Brick" blockNamespace=output inlineInputMode="inline"
|
||||
//% x.min=0 x.max=178 y.min=0 y.max=128
|
||||
export function print(text: string, x: number, y: number, mode = Draw.Normal) {
|
||||
x |= 0
|
||||
y |= 0
|
||||
if (!currFont) currFont = defaultFont()
|
||||
|
2
libs/core/shims.d.ts
vendored
2
libs/core/shims.d.ts
vendored
@ -51,7 +51,7 @@ declare namespace control {
|
||||
* @param mode optional definition of how the event should be processed after construction.
|
||||
*/
|
||||
//% weight=21 blockGap=12 blockId="control_raise_event"
|
||||
//% block="raise event|from %src|with value value" blockExternalInputs=1 shim=control::raiseEvent
|
||||
//% block="raise event|from %src|with value %value" blockExternalInputs=1 shim=control::raiseEvent
|
||||
function raiseEvent(src: int32, value: int32): void;
|
||||
|
||||
/**
|
||||
|
@ -1,10 +1,10 @@
|
||||
screen.clear()
|
||||
screen.drawText(10, 30, "PXT!", Draw.Quad)
|
||||
screen.print("PXT!", 10, 30, Draw.Quad)
|
||||
|
||||
screen.drawRect(40, 40, 20, 10, Draw.Fill)
|
||||
output.setLights(LightsPattern.Orange)
|
||||
output.setStatusLight(LightsPattern.Orange)
|
||||
|
||||
screen.drawIcon(100, 50, screen.doubleIcon(screen.heart), Draw.Double|Draw.Transparent)
|
||||
screen.drawIcon(100, 50, screen.doubleIcon(screen.heart), Draw.Double | Draw.Transparent)
|
||||
|
||||
input.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
||||
screen.clear()
|
||||
@ -12,37 +12,37 @@ input.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
||||
|
||||
input.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||
output.setLights(LightsPattern.Red)
|
||||
output.setStatusLight(LightsPattern.Red)
|
||||
screen.setFont(screen.microbitFont())
|
||||
})
|
||||
|
||||
input.buttonRight.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText(10, 60, "Right!")
|
||||
screen.print("Right!", 10, 60)
|
||||
})
|
||||
|
||||
input.buttonDown.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText(10, 60, "Down! ")
|
||||
screen.print("Down! ", 10, 60)
|
||||
})
|
||||
|
||||
input.buttonUp.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText(10, 60, "Up! ")
|
||||
screen.print("Up! ", 10, 60)
|
||||
})
|
||||
|
||||
|
||||
let num = 0
|
||||
|
||||
input.touchSensor.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText(10, 60, "Click! " + num)
|
||||
input.touchSensor1.onEvent(TouchSensorEvent.Bumped, () => {
|
||||
screen.print("Click! " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
input.remoteTopLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawText(10, 60, "TOPLEFT " + num)
|
||||
screen.print("TOPLEFT " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
input.remoteTopRight.onEvent(ButtonEvent.Down, () => {
|
||||
screen.drawText(10, 60, "TOPRIGH " + num)
|
||||
screen.print("TOPRIGH " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
@ -54,7 +54,7 @@ loops.forever(() => {
|
||||
/*
|
||||
loops.forever(() => {
|
||||
let v = input.color.getColor()
|
||||
screen.drawText(10, 60, v + " ")
|
||||
screen.print(10, 60, v + " ")
|
||||
loops.pause(200)
|
||||
})
|
||||
*/
|
||||
*/
|
||||
|
@ -1,10 +1,26 @@
|
||||
namespace input {
|
||||
export class TouchSensor extends internal.AnalogSensor {
|
||||
button: Button;
|
||||
// keep TouchSensorEvent in sync with ButtonEvent
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.button = new Button()
|
||||
/**
|
||||
* Touch sensor interactions
|
||||
*/
|
||||
const enum TouchSensorEvent {
|
||||
//% block="touched"
|
||||
Touched = 4,
|
||||
//% block="bumped"
|
||||
Bumped = 1,
|
||||
//% block="released"
|
||||
Released = 3,
|
||||
}
|
||||
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class TouchSensor extends internal.AnalogSensor {
|
||||
private button: Button;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.button = new Button();
|
||||
}
|
||||
|
||||
_query() {
|
||||
@ -18,11 +34,45 @@ namespace input {
|
||||
_deviceType() {
|
||||
return DAL.DEVICE_TYPE_TOUCH
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if touch sensor is touched.
|
||||
* @param sensor the port to query the request
|
||||
*/
|
||||
//% help=input/touch/is-touched
|
||||
//% block="%sensor|is touched"
|
||||
//% blockId=touchIsTouched
|
||||
//% parts="touch"
|
||||
//% blockNamespace=input
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
isTouched() {
|
||||
return this.button.isPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a touch sensor is touched...
|
||||
* @param sensor the touch sensor that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
*/
|
||||
//% help=input/touch/on-event
|
||||
//% blockId=touchEvent block="on %sensor|%event"
|
||||
//% parts="touch"
|
||||
//% blockNamespace=input
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
onEvent(ev: TouchSensorEvent, body: () => void) {
|
||||
this.button.onEvent(<ButtonEvent><number>ev, body)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const touchSensorImpl: TouchSensor = new TouchSensor()
|
||||
|
||||
//% whenUsed
|
||||
export const touchSensor: Button = touchSensorImpl.button
|
||||
//% whenUsed block="touch sensor 1" weight=95 fixedInstance
|
||||
export const touchSensor1: TouchSensor = new TouchSensor(1)
|
||||
//% whenUsed block="touch sensor 2" weight=95 fixedInstance
|
||||
export const touchSensor2: TouchSensor = new TouchSensor(2)
|
||||
//% whenUsed block="touch sensor 3" weight=95 fixedInstance
|
||||
export const touchSensor3: TouchSensor = new TouchSensor(3)
|
||||
//% whenUsed block="touch sensor 4" weight=95 fixedInstance
|
||||
export const touchSensor4: TouchSensor = new TouchSensor(4)
|
||||
}
|
||||
|
@ -1,22 +1,42 @@
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class UltraSonicSensor extends internal.UartSensor {
|
||||
constructor() {
|
||||
super()
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
return DAL.DEVICE_TYPE_ULTRASONIC
|
||||
}
|
||||
|
||||
/** Get distance in mm */
|
||||
getDistance() {
|
||||
/**
|
||||
* Gets the distance from the sonar in millimeters
|
||||
* @param sensor the ultrasonic sensor port
|
||||
*/
|
||||
//% help=input/ultrasonic/distance
|
||||
//% block="%sensor|distance"
|
||||
//% blockId=sonarGetDistance
|
||||
//% parts="ultrasonic"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Ultrasonic Sensor"
|
||||
distance() {
|
||||
// it supposedly also has an inch mode, but we stick to mm
|
||||
this._setMode(0)
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const ultrasonic: UltraSonicSensor = new UltraSonicSensor()
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 4"
|
||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 1"
|
||||
export const ultrasonic1: UltraSonicSensor = new UltraSonicSensor(1)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 2"
|
||||
export const ultrasonic2: UltraSonicSensor = new UltraSonicSensor(2)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic sensor 3"
|
||||
export const ultrasonic3: UltraSonicSensor = new UltraSonicSensor(3)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace input {
|
||||
}
|
||||
|
||||
//% color="#8AC044" weight=90 icon="\uf185"
|
||||
//% groups='["Motors", "Brick"]'
|
||||
namespace output {
|
||||
}
|
||||
|
||||
|
@ -8,15 +8,15 @@
|
||||
"music.noteFrequency|param|name": "the note name, eg: Note.C",
|
||||
"music.playSound": "Start playing a sound and don't wait for it to finish.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
|
||||
"music.playSoundUntilDone": "Play a sound and wait until the sound is done.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
|
||||
"music.playSoundUntilDone|param|sound": "the melody to play, eg: 'g5:1'",
|
||||
"music.playSound|param|sound": "the melody to play, eg: 'g5:1'",
|
||||
"music.playSoundUntilDone|param|sound": "the melody to play, eg: music.sounds(Sounds.PowerUp)",
|
||||
"music.playSound|param|sound": "the melody to play, eg: music.sounds(Sounds.PowerUp)",
|
||||
"music.playTone": "Play a tone through the speaker for some amount of time.",
|
||||
"music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
|
||||
"music.playTone|param|ms": "tone duration in milliseconds (ms)",
|
||||
"music.rest": "Rest, or play silence, for some time (in milleseconds).",
|
||||
"music.rest|param|ms": "rest duration in milliseconds (ms)",
|
||||
"music.rest|param|ms": "rest duration in milliseconds (ms), eg: 100",
|
||||
"music.ringTone": "Play a tone.",
|
||||
"music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
|
||||
"music.ringTone|param|frequency": "pitch of the tone to play in Hertz (Hz), eg: Note.C",
|
||||
"music.setTempo": "Set the tempo a number of beats per minute (bpm).",
|
||||
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
|
||||
"music.setVolume": "Set the output volume of the sound synthesizer.",
|
||||
|
@ -29,14 +29,14 @@
|
||||
"Sounds.Siren|block": "siren",
|
||||
"Sounds.Wawawawaa|block": "wawawawaa",
|
||||
"music.beat|block": "%fraction|beat",
|
||||
"music.changeTempoBy|block": "change tempo by (bpm)|%value",
|
||||
"music.changeTempoBy|block": "change tempo by %value|(bpm)",
|
||||
"music.noteFrequency|block": "%note",
|
||||
"music.playSoundUntilDone|block": "play sound %sound=music_sounds|until done",
|
||||
"music.playSound|block": "play sound %sound=music_sounds",
|
||||
"music.playTone|block": "play tone|at %note=device_note|for %duration=device_beat",
|
||||
"music.rest|block": "rest|for %duration=device_beat",
|
||||
"music.ringTone|block": "ring tone|at %note=device_note",
|
||||
"music.setTempo|block": "set tempo to (bpm)|%value",
|
||||
"music.setTempo|block": "set tempo to %value|(bpm)",
|
||||
"music.setVolume|block": "set volume %volume",
|
||||
"music.sounds|block": "%name",
|
||||
"music.stopAllSounds|block": "stop all sounds",
|
||||
|
@ -67,10 +67,11 @@ static void _playTone(uint16_t frequency, uint16_t duration, uint8_t volume)
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||
* @param ms tone duration in milliseconds (ms)
|
||||
*/
|
||||
//% help=music/play-tone weight=90
|
||||
//% help=music/play-tone
|
||||
//% blockId=music_play_note block="play tone|at %note=device_note|for %duration=device_beat"
|
||||
//% parts="headphone" async blockGap=8
|
||||
//% parts="headphone" async
|
||||
//% blockNamespace=music
|
||||
//% weight=76 blockGap=8
|
||||
void playTone(int frequency, int ms) {
|
||||
if (frequency <= 0) {
|
||||
_stopSound();
|
||||
|
7
libs/music/shims.d.ts
vendored
7
libs/music/shims.d.ts
vendored
@ -18,10 +18,11 @@ declare namespace music {
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||
* @param ms tone duration in milliseconds (ms)
|
||||
*/
|
||||
//% help=music/play-tone weight=90
|
||||
//% help=music/play-tone
|
||||
//% blockId=music_play_note block="play tone|at %note=device_note|for %duration=device_beat"
|
||||
//% parts="headphone" async blockGap=8
|
||||
//% blockNamespace=music shim=music::playTone
|
||||
//% parts="headphone" async
|
||||
//% blockNamespace=music
|
||||
//% weight=76 blockGap=8 shim=music::playTone
|
||||
function playTone(frequency: int32, ms: int32): void;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.23",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@ -39,8 +39,8 @@
|
||||
"semantic-ui-less": "^2.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.9.1",
|
||||
"pxt-core": "1.8.10"
|
||||
"pxt-common-packages": "0.11.7",
|
||||
"pxt-core": "2.3.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
@ -68,10 +68,10 @@
|
||||
"appTheme": {
|
||||
"accentColor": "#0089BF",
|
||||
"logoUrl": "https://lego.makecode.com",
|
||||
"logo": "./static/logo.svg",
|
||||
"docsLogo": "./static/logo.square.svg",
|
||||
"portraitLogo": "./static/logo.square.svg",
|
||||
"footerLogo": "./static/logo.square.svg",
|
||||
"logo": "./static/lego_education_logo.png",
|
||||
"docsLogo": "./static/lego-logo.svg",
|
||||
"portraitLogo": "./static/lego-logo.svg",
|
||||
"footerLogo": "./static/lego-logo.svg",
|
||||
"cardLogo": "./static/icons/android-chrome-192x192.png",
|
||||
"appLogo": "./static/icons/android-chrome-192x192.png",
|
||||
"organization": "Microsoft MakeCode",
|
||||
@ -89,10 +89,6 @@
|
||||
"name": "About",
|
||||
"path": "/about"
|
||||
},
|
||||
{
|
||||
"name": "Examples",
|
||||
"path": "#projects:Examples"
|
||||
},
|
||||
{
|
||||
"name": "Blocks",
|
||||
"path": "/blocks"
|
||||
@ -110,16 +106,12 @@
|
||||
"path": "https://www.lego.com/en-us/mindstorms/products/mindstorms-ev3-31313"
|
||||
}
|
||||
],
|
||||
"galleries": {
|
||||
"Make": "projects",
|
||||
"Examples": "examples"
|
||||
},
|
||||
"sideDoc": "tutorials/getting-started",
|
||||
"showHomeScreen": true,
|
||||
"homeScreenHero": "./static/hero.png",
|
||||
"invertedMenu": false,
|
||||
"invertedMonaco": false,
|
||||
"monacoToolbox": true,
|
||||
"invertedToolbox": true,
|
||||
"exampleGallery": "examples",
|
||||
"hasAudio": true,
|
||||
"usbHelp": [],
|
||||
"extendEditor": true,
|
||||
|
@ -25,7 +25,7 @@ namespace pxsim {
|
||||
export class DalBoard extends CoreBoard implements
|
||||
AccelerometerBoard,
|
||||
CommonBoard,
|
||||
LightBoard,
|
||||
// LightBoard,
|
||||
LightSensorBoard,
|
||||
MicrophoneBoard,
|
||||
MusicBoard,
|
||||
@ -34,7 +34,7 @@ namespace pxsim {
|
||||
InfraredBoard,
|
||||
CapTouchBoard {
|
||||
// state & update logic for component services
|
||||
neopixelState: CommonNeoPixelState;
|
||||
// neopixelState: CommonNeoPixelState;
|
||||
buttonState: EV3ButtonState;
|
||||
slideSwitchState: SlideSwitchState;
|
||||
lightSensorState: AnalogSensorState;
|
||||
@ -62,11 +62,12 @@ namespace pxsim {
|
||||
this.builtinParts["buttons"] = this.buttonState = new EV3ButtonState();
|
||||
this.builtinParts["light"] = this.lightState = new EV3LightState();
|
||||
this.builtinParts["screen"] = this.screenState = new EV3ScreenState();
|
||||
this.builtinParts["audio"] = this.audioState = new AudioState();
|
||||
|
||||
/*this.builtinParts["neopixel"] = this.neopixelState = new CommonNeoPixelState();
|
||||
this.builtinParts["buttonpair"] = this.buttonState = new CommonButtonState();
|
||||
|
||||
this.builtinParts["switch"] = this.slideSwitchState = new SlideSwitchState();
|
||||
this.builtinParts["audio"] = this.audioState = new AudioState();
|
||||
this.builtinParts["lightsensor"] = this.lightSensorState = new AnalogSensorState(DAL.DEVICE_ID_LIGHT_SENSOR, 0, 255);
|
||||
this.builtinParts["thermometer"] = this.thermometerState = new AnalogSensorState(DAL.DEVICE_ID_THERMOMETER, -5, 50);
|
||||
this.builtinParts["soundsensor"] = this.microphoneState = new AnalogSensorState(DAL.DEVICE_ID_TOUCH_SENSOR + 1, 0, 255);
|
||||
@ -174,9 +175,9 @@ namespace pxsim {
|
||||
return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
|
||||
}
|
||||
|
||||
defaultNeopixelPin() {
|
||||
return this.edgeConnectorState.getPin(CPlayPinName.D8);
|
||||
}
|
||||
//defaultNeopixelPin() {
|
||||
// return this.edgeConnectorState.getPin(CPlayPinName.D8);
|
||||
//}
|
||||
|
||||
getDefaultPitchPin() {
|
||||
return this.edgeConnectorState.getPin(CPlayPinName.D6);
|
||||
|
@ -480,6 +480,7 @@ namespace pxsim.visuals {
|
||||
this.screenCanvasCtx.putImageData(this.screenCanvasData, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
private updateNeoPixels() {
|
||||
let state = this.board;
|
||||
if (!state || !state.neopixelState) return;
|
||||
@ -509,6 +510,7 @@ namespace pxsim.visuals {
|
||||
if (p_inner) svg.filter(p_inner, `url(#neopixelglow)`);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private updateSound() {
|
||||
let state = this.board;
|
||||
|
52
theme/blockly.less
Normal file
52
theme/blockly.less
Normal file
@ -0,0 +1,52 @@
|
||||
@import 'themes/default/globals/site.variables';
|
||||
@import 'themes/pxt/globals/site.variables';
|
||||
@import 'site/globals/site.variables';
|
||||
|
||||
@import 'blockly-core';
|
||||
|
||||
/* Toolbox padding */
|
||||
.blocklyToolboxDiv, .monacoToolboxDiv {
|
||||
padding: 0.5rem;
|
||||
-webkit-box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.31);
|
||||
-moz-box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.31);
|
||||
box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.31);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
div.blocklyTreeRow {
|
||||
border-radius: 0px;
|
||||
-webkit-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.1);
|
||||
-moz-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.1);
|
||||
box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* Remove shadow around blockly blocks */
|
||||
.blocklyPathDark, .blocklyPathLight {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Blockly Text */
|
||||
span.blocklyTreeLabel {
|
||||
font-family: @pageFont !important;
|
||||
text-transform: uppercase !important;
|
||||
font-size:1rem !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Search box */
|
||||
#blocklySearchArea {
|
||||
margin: 0.5rem;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
.blocklySearchInputField {
|
||||
border-radius: 1rem !important;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media only screen and (max-width: @largestMobileScreen) {
|
||||
#blocklyTrashIcon {
|
||||
margin: 0.2rem;
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@
|
||||
|
||||
/* Lego colors */
|
||||
@red: @brightRed;
|
||||
@blue: #008ad2;
|
||||
@blue: #00a5c8; /*#008ad2;*/
|
||||
@yellow: #fccd00;
|
||||
@orange: #fa7f2a;
|
||||
@green: @brightYellowishGreen;
|
||||
@ -96,9 +96,11 @@
|
||||
Menu
|
||||
--------------------*/
|
||||
|
||||
@mainMenuBackground: #f4f7f9;
|
||||
@mainMenuInvertedBackground: @yellow;
|
||||
@mainMenuTutorialBackground: @orange;
|
||||
|
||||
|
||||
@tutorialSelectedMenuColor: @blue;
|
||||
|
||||
/*-------------------
|
||||
@ -117,6 +119,8 @@
|
||||
@editorToolsBackground: #fcfbfa;
|
||||
@blocklySvgColor: #ecf6ff;
|
||||
|
||||
@homeScreenBackground: #EAEEEF;
|
||||
|
||||
/*-------------------
|
||||
Full screen
|
||||
--------------------*/
|
||||
@ -152,3 +156,13 @@
|
||||
@blocklyRowHeightComputer: 50px;
|
||||
@blocklyRowHeightTablet: 50px;
|
||||
@blocklyRowHeightMobile: 50px;
|
||||
|
||||
|
||||
/*-------------------
|
||||
Flyout
|
||||
--------------------*/
|
||||
|
||||
@flyoutLabelColor: white;
|
||||
@blocklyFlyoutColor: #282828;
|
||||
@blocklyFlyoutColorOpacity: 0.9;
|
||||
@monacoFlyoutColor: rgba(40, 40, 40,0.9);
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
/* Menu bar colors */
|
||||
#menubar .ui.item {
|
||||
color: @red;
|
||||
color: #373737;
|
||||
}
|
||||
.fullscreensim #menubar .ui.menu {
|
||||
box-shadow: none !important;
|
||||
@ -56,63 +56,19 @@
|
||||
min-width: 2.0rem;
|
||||
}
|
||||
|
||||
/* Toolbox padding */
|
||||
.blocklyToolboxDiv, .monacoToolboxDiv {
|
||||
padding: 0.5rem;
|
||||
-webkit-box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.31);
|
||||
-moz-box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.31);
|
||||
box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.31);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
div.blocklyTreeRow {
|
||||
border-radius: 0px;
|
||||
-webkit-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.1);
|
||||
-moz-box-shadow: inset 0px 0px 0px 3px rgba(0,0,0,0.1);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Blockly Text */
|
||||
span.blocklyTreeLabel {
|
||||
font-family: @pageFont !important;
|
||||
text-transform: uppercase !important;
|
||||
font-size:1rem !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.blocklyFlyoutBackground {
|
||||
fill: #282828 !important;
|
||||
}
|
||||
.monacoFlyout {
|
||||
background: rgba(40, 40, 40, 0.9);
|
||||
}
|
||||
|
||||
/* Editor menu toggle */
|
||||
#menubar .ui.menu .item.editor-menuitem {
|
||||
#menubar .ui.menu.fixed .item.editor-menuitem .ui.grid {
|
||||
background: @blue !important;
|
||||
border-radius: 0px !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 */
|
||||
#blocklySearchArea {
|
||||
margin: 0.5rem;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
#menubar .ui.menu.fixed .ui.item.editor-menuitem .item {
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
.blocklySearchInputField {
|
||||
border-radius: 1rem !important;
|
||||
#menubar .ui.menu.fixed .ui.item.editor-menuitem .item.active {
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
.sandboxfooter a:not(.thin) {
|
||||
@ -124,41 +80,18 @@ span.blocklyTreeLabel {
|
||||
#filelist {
|
||||
background: transparent;
|
||||
}
|
||||
div.blocklyTreeRow {
|
||||
padding-bottom: 2rem !important;
|
||||
min-height: @blocklyRowHeightMobile;
|
||||
line-height: @blocklyRowHeightMobile/2;
|
||||
}
|
||||
#blocklyTrashIcon {
|
||||
margin: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
@ -49,10 +49,10 @@
|
||||
/* Modules */
|
||||
@accordion : 'default';
|
||||
@checkbox : 'default';
|
||||
@dimmer : 'default';
|
||||
@dimmer : 'pxt';
|
||||
@dropdown : 'default';
|
||||
@embed : 'default';
|
||||
@modal : 'default';
|
||||
@modal : 'pxt';
|
||||
@nag : 'default';
|
||||
@popup : 'default';
|
||||
@progress : 'default';
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
/* Views */
|
||||
@ad : 'default';
|
||||
@card : 'default';
|
||||
@card : 'pxt';
|
||||
@comment : 'default';
|
||||
@feed : 'default';
|
||||
@item : 'default';
|
||||
|
Reference in New Issue
Block a user