2.1.28, initiation update to PXT v5.28.24 (#54)
@ -1,373 +0,0 @@
|
||||
#include "MicroBit.h"
|
||||
#include "ManagedBuffer.h"
|
||||
#include <limits.h>
|
||||
|
||||
static const char empty[] __attribute__ ((aligned (4))) = "\xff\xff\0\0\0";
|
||||
|
||||
/**
|
||||
* Internal constructor helper.
|
||||
* Configures this ManagedBuffer to refer to the static empty buffer.
|
||||
*/
|
||||
void ManagedBuffer::initEmpty()
|
||||
{
|
||||
ptr = (BufferData*)(void*)empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
* Creates an empty ManagedBuffer.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p();
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer::ManagedBuffer()
|
||||
{
|
||||
initEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates an empty ManagedBuffer of the given size.
|
||||
*
|
||||
* @param length The length of the buffer to create.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p(16); // Creates a ManagedBuffer 16 bytes long.
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer::ManagedBuffer(int length)
|
||||
{
|
||||
this->init(NULL, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a new ManagedBuffer of the given size,
|
||||
* and fills it with the data provided.
|
||||
*
|
||||
* @param data The data with which to fill the buffer.
|
||||
* @param length The length of the buffer to create.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uint8_t buf = {13,5,2};
|
||||
* ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long.
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer::ManagedBuffer(uint8_t *data, int length)
|
||||
{
|
||||
this->init(data, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
* Add ourselves as a reference to an existing ManagedBuffer.
|
||||
*
|
||||
* @param buffer The ManagedBuffer to reference.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p();
|
||||
* ManagedBuffer p2(i); // Refers to the same buffer as p.
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer::ManagedBuffer(const ManagedBuffer &buffer)
|
||||
{
|
||||
ptr = buffer.ptr;
|
||||
ptr->incr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes.
|
||||
*
|
||||
* @param p The pointer to use.
|
||||
*/
|
||||
ManagedBuffer::ManagedBuffer(BufferData *p)
|
||||
{
|
||||
ptr = p;
|
||||
ptr->incr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal constructor-initialiser.
|
||||
*
|
||||
* @param data The data with which to fill the buffer.
|
||||
* @param length The length of the buffer to create.
|
||||
*
|
||||
*/
|
||||
void ManagedBuffer::init(uint8_t *data, int length)
|
||||
{
|
||||
if (length <= 0) {
|
||||
initEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = (BufferData *) malloc(sizeof(BufferData) + length);
|
||||
ptr->init();
|
||||
|
||||
ptr->length = length;
|
||||
|
||||
// Copy in the data buffer, if provided.
|
||||
if (data)
|
||||
memcpy(ptr->payload, data, length);
|
||||
else
|
||||
memset(ptr->payload, 0, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* Removes buffer resources held by the instance.
|
||||
*/
|
||||
ManagedBuffer::~ManagedBuffer()
|
||||
{
|
||||
ptr->decr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy assign operation.
|
||||
*
|
||||
* Called when one ManagedBuffer is assigned the value of another using the '=' operator.
|
||||
* Decrements our reference count and free up the buffer as necessary.
|
||||
* Then, update our buffer to refer to that of the supplied ManagedBuffer,
|
||||
* and increase its reference count.
|
||||
*
|
||||
* @param p The ManagedBuffer to reference.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uint8_t buf = {13,5,2};
|
||||
* ManagedBuffer p1(16);
|
||||
* ManagedBuffer p2(buf, 3);
|
||||
*
|
||||
* p1 = p2;
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer& ManagedBuffer::operator = (const ManagedBuffer &p)
|
||||
{
|
||||
if(ptr == p.ptr)
|
||||
return *this;
|
||||
|
||||
ptr->decr();
|
||||
ptr = p.ptr;
|
||||
ptr->incr();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality operation.
|
||||
*
|
||||
* Called when one ManagedBuffer is tested to be equal to another using the '==' operator.
|
||||
*
|
||||
* @param p The ManagedBuffer to test ourselves against.
|
||||
* @return true if this ManagedBuffer is identical to the one supplied, false otherwise.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
*
|
||||
* uint8_t buf = {13,5,2};
|
||||
* ManagedBuffer p1(16);
|
||||
* ManagedBuffer p2(buf, 3);
|
||||
*
|
||||
* if(p1 == p2) // will be true
|
||||
* uBit.display.scroll("same!");
|
||||
* @endcode
|
||||
*/
|
||||
bool ManagedBuffer::operator== (const ManagedBuffer& p)
|
||||
{
|
||||
if (ptr == p.ptr)
|
||||
return true;
|
||||
else
|
||||
return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length)==0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the byte at the given index to value provided.
|
||||
* @param position The index of the byte to change.
|
||||
* @param value The new value of the byte (0-255).
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* p1.setByte(0,255); // Sets the firts byte in the buffer to the value 255.
|
||||
* @endcode
|
||||
*/
|
||||
int ManagedBuffer::setByte(int position, uint8_t value)
|
||||
{
|
||||
if (0 <= position && position < ptr->length)
|
||||
{
|
||||
ptr->payload[position] = value;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the value of the given byte in the buffer.
|
||||
*
|
||||
* @param position The index of the byte to read.
|
||||
* @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* p1.setByte(0,255); // Sets the firts byte in the buffer to the value 255.
|
||||
* p1.getByte(0); // Returns 255.
|
||||
* @endcode
|
||||
*/
|
||||
int ManagedBuffer::getByte(int position)
|
||||
{
|
||||
if (0 <= position && position < ptr->length)
|
||||
return ptr->payload[position];
|
||||
else
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ptr, do not decr() it, and set the current instance to an empty buffer.
|
||||
* This is to be used by specialized runtimes which pass BufferData around.
|
||||
*/
|
||||
BufferData *ManagedBuffer::leakData()
|
||||
{
|
||||
BufferData* res = ptr;
|
||||
initEmpty();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int ManagedBuffer::fill(uint8_t value, int offset, int length)
|
||||
{
|
||||
if (offset < 0 || offset > ptr->length)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
if (length < 0)
|
||||
length = ptr->length;
|
||||
length = min(length, ptr->length - offset);
|
||||
|
||||
memset(ptr->payload + offset, value, length);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
ManagedBuffer ManagedBuffer::slice(int offset, int length) const
|
||||
{
|
||||
offset = min(ptr->length, offset);
|
||||
if (length < 0)
|
||||
length = ptr->length;
|
||||
length = min(length, ptr->length - offset);
|
||||
return ManagedBuffer(ptr->payload + offset, length);
|
||||
}
|
||||
|
||||
void ManagedBuffer::shift(int offset, int start, int len)
|
||||
{
|
||||
if (len < 0) len = ptr->length - start;
|
||||
if (start < 0 || start + len > ptr->length || start + len < start
|
||||
|| len == 0 || offset == 0 || offset == INT_MIN) return;
|
||||
if (offset <= -len || offset >= len) {
|
||||
fill(0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *data = ptr->payload + start;
|
||||
if (offset < 0) {
|
||||
offset = -offset;
|
||||
memmove(data + offset, data, len - offset);
|
||||
memset(data, 0, offset);
|
||||
} else {
|
||||
len = len - offset;
|
||||
memmove(data, data + offset, len);
|
||||
memset(data + len, 0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedBuffer::rotate(int offset, int start, int len)
|
||||
{
|
||||
if (len < 0) len = ptr->length - start;
|
||||
if (start < 0 || start + len > ptr-> length || start + len < start
|
||||
|| len == 0 || offset == 0 || offset == INT_MIN) return;
|
||||
|
||||
if (offset < 0)
|
||||
offset += len << 8; // try to make it positive
|
||||
offset %= len;
|
||||
if (offset < 0)
|
||||
offset += len;
|
||||
|
||||
uint8_t *data = ptr->payload + start;
|
||||
|
||||
uint8_t *n_first = data + offset;
|
||||
uint8_t *first = data;
|
||||
uint8_t *next = n_first;
|
||||
uint8_t *last = data + len;
|
||||
|
||||
while (first != next) {
|
||||
uint8_t tmp = *first;
|
||||
*first++ = *next;
|
||||
*next++ = tmp;
|
||||
if (next == last) {
|
||||
next = n_first;
|
||||
} else if (first == n_first) {
|
||||
n_first = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ManagedBuffer::writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset, int length)
|
||||
{
|
||||
if (length < 0)
|
||||
length = src.length();
|
||||
|
||||
if (srcOffset < 0 || dstOffset < 0 || dstOffset > ptr->length)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
length = min(src.length() - srcOffset, ptr->length - dstOffset);
|
||||
|
||||
if (length < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (ptr == src.ptr) {
|
||||
memmove(getBytes() + dstOffset, src.ptr->payload + srcOffset, length);
|
||||
} else {
|
||||
memcpy(getBytes() + dstOffset, src.ptr->payload + srcOffset, length);
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
int ManagedBuffer::writeBytes(int offset, uint8_t *src, int length, bool swapBytes)
|
||||
{
|
||||
if (offset < 0 || length < 0 || offset + length > ptr->length)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (swapBytes) {
|
||||
uint8_t *p = ptr->payload + offset + length;
|
||||
for (int i = 0; i < length; ++i)
|
||||
*--p = src[i];
|
||||
} else {
|
||||
memcpy(ptr->payload + offset, src, length);
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
int ManagedBuffer::readBytes(uint8_t *dst, int offset, int length, bool swapBytes) const
|
||||
{
|
||||
if (offset < 0 || length < 0 || offset + length > ptr->length)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (swapBytes) {
|
||||
uint8_t *p = ptr->payload + offset + length;
|
||||
for (int i = 0; i < length; ++i)
|
||||
dst[i] = *--p;
|
||||
} else {
|
||||
memcpy(dst, ptr->payload + offset, length);
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
#ifndef MICROBIT_MANAGED_BUFFER_H
|
||||
#define MICROBIT_MANAGED_BUFFER_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "RefCounted.h"
|
||||
|
||||
struct BufferData : RefCounted
|
||||
{
|
||||
uint16_t length; // The length of the payload in bytes
|
||||
uint8_t payload[0]; // ManagedBuffer data
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition for a ManagedBuffer.
|
||||
* A ManagedBuffer holds a series of bytes, used with MicroBitRadio channels and in other places.
|
||||
* n.b. This is a mutable, managed type.
|
||||
*/
|
||||
class ManagedBuffer
|
||||
{
|
||||
BufferData *ptr; // Pointer to payload data
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
* Creates an empty ManagedBuffer. The 'ptr' field in all empty buffers is shared.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p();
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a new ManagedBuffer of the given size.
|
||||
*
|
||||
* @param length The length of the buffer to create.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p(16); // Creates a ManagedBuffer 16 bytes long.
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer(int length);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates an empty ManagedBuffer of the given size,
|
||||
* and fills it with the data provided.
|
||||
*
|
||||
* @param data The data with which to fill the buffer.
|
||||
* @param length The length of the buffer to create.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uint8_t buf[] = {13,5,2};
|
||||
* ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long.
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer(uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
* Add ourselves as a reference to an existing ManagedBuffer.
|
||||
*
|
||||
* @param buffer The ManagedBuffer to reference.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p();
|
||||
* ManagedBuffer p2(i); // Refers to the same buffer as p.
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer(const ManagedBuffer &buffer);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes.
|
||||
*
|
||||
* @param p The pointer to use.
|
||||
*/
|
||||
ManagedBuffer(BufferData *p);
|
||||
|
||||
/**
|
||||
* Internal constructor helper.
|
||||
* Configures this ManagedBuffer to refer to the static empty buffer.
|
||||
*/
|
||||
void initEmpty();
|
||||
|
||||
/**
|
||||
* Internal constructor-initialiser.
|
||||
*
|
||||
* @param data The data with which to fill the buffer.
|
||||
* @param length The length of the buffer to create.
|
||||
*
|
||||
*/
|
||||
void init(uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* Removes buffer resources held by the instance.
|
||||
*/
|
||||
~ManagedBuffer();
|
||||
|
||||
/**
|
||||
* Provide an array containing the buffer data.
|
||||
* @return The contents of this buffer, as an array of bytes.
|
||||
*/
|
||||
uint8_t *getBytes()
|
||||
{
|
||||
return ptr->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ptr, do not decr() it, and set the current instance to an empty buffer.
|
||||
* This is to be used by specialized runtimes which pass BufferData around.
|
||||
*/
|
||||
BufferData *leakData();
|
||||
|
||||
/**
|
||||
* Copy assign operation.
|
||||
*
|
||||
* Called when one ManagedBuffer is assigned the value of another using the '=' operator.
|
||||
* Decrements our reference count and free up the buffer as necessary.
|
||||
* Then, update our buffer to refer to that of the supplied ManagedBuffer,
|
||||
* and increase its reference count.
|
||||
*
|
||||
* @param p The ManagedBuffer to reference.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uint8_t buf = {13,5,2};
|
||||
* ManagedBuffer p1(16);
|
||||
* ManagedBuffer p2(buf, 3);
|
||||
*
|
||||
* p1 = p2;
|
||||
* @endcode
|
||||
*/
|
||||
ManagedBuffer& operator = (const ManagedBuffer& p);
|
||||
|
||||
/**
|
||||
* Array access operation (read).
|
||||
*
|
||||
* Called when a ManagedBuffer is dereferenced with a [] operation.
|
||||
* Transparently map this through to the underlying payload for elegance of programming.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* uint8_t data = p1[0];
|
||||
* @endcode
|
||||
*/
|
||||
uint8_t operator [] (int i) const
|
||||
{
|
||||
return ptr->payload[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Array access operation (modify).
|
||||
*
|
||||
* Called when a ManagedBuffer is dereferenced with a [] operation.
|
||||
* Transparently map this through to the underlying payload for elegance of programming.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* p1[0] = 42;
|
||||
* @endcode
|
||||
*/
|
||||
uint8_t& operator [] (int i)
|
||||
{
|
||||
return ptr->payload[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality operation.
|
||||
*
|
||||
* Called when one ManagedBuffer is tested to be equal to another using the '==' operator.
|
||||
*
|
||||
* @param p The ManagedBuffer to test ourselves against.
|
||||
* @return true if this ManagedBuffer is identical to the one supplied, false otherwise.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
*
|
||||
* uint8_t buf = {13,5,2};
|
||||
* ManagedBuffer p1(16);
|
||||
* ManagedBuffer p2(buf, 3);
|
||||
*
|
||||
* if(p1 == p2) // will be true
|
||||
* uBit.display.scroll("same!");
|
||||
* @endcode
|
||||
*/
|
||||
bool operator== (const ManagedBuffer& p);
|
||||
|
||||
/**
|
||||
* Sets the byte at the given index to value provided.
|
||||
* @param position The index of the byte to change.
|
||||
* @param value The new value of the byte (0-255).
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* p1.setByte(0,255); // Sets the first byte in the buffer to the value 255.
|
||||
* @endcode
|
||||
*/
|
||||
int setByte(int position, uint8_t value);
|
||||
|
||||
/**
|
||||
* Determines the value of the given byte in the buffer.
|
||||
*
|
||||
* @param position The index of the byte to read.
|
||||
* @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* p1.setByte(0,255); // Sets the first byte in the buffer to the value 255.
|
||||
* p1.getByte(0); // Returns 255.
|
||||
* @endcode
|
||||
*/
|
||||
int getByte(int position);
|
||||
|
||||
/**
|
||||
* Gets number of bytes in this buffer
|
||||
* @return The size of the buffer in bytes.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedBuffer p1(16);
|
||||
* p1.length(); // Returns 16.
|
||||
* @endcode
|
||||
*/
|
||||
int length() const { return ptr->length; }
|
||||
|
||||
int fill(uint8_t value, int offset = 0, int length = -1);
|
||||
|
||||
ManagedBuffer slice(int offset = 0, int length = -1) const;
|
||||
|
||||
void shift(int offset, int start = 0, int length = -1);
|
||||
|
||||
void rotate(int offset, int start = 0, int length = -1);
|
||||
|
||||
int readBytes(uint8_t *dst, int offset, int length, bool swapBytes = false) const;
|
||||
|
||||
int writeBytes(int dstOffset, uint8_t *src, int length, bool swapBytes = false);
|
||||
|
||||
int writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset = 0, int length = -1);
|
||||
|
||||
bool isReadOnly() const { return ptr->isReadOnly(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -3,37 +3,39 @@
|
||||
"AcceleratorRange.FourG": "The accelerator measures forces up to 4 gravity",
|
||||
"AcceleratorRange.OneG": "The accelerator measures forces up to 1 gravity",
|
||||
"AcceleratorRange.TwoG": "The accelerator measures forces up to 2 gravity",
|
||||
"Array": "Add, remove, and replace items in lists.\n\nAdd, remove, and replace items in lists.",
|
||||
"Array": "Add, remove, and replace items in lists.",
|
||||
"Array.concat": "Concatenates the values with another array.",
|
||||
"Array.concat|param|arr": "The other array that is being concatenated with",
|
||||
"Array.every": "Tests whether all elements in the array pass the test implemented by the provided function.",
|
||||
"Array.every|param|callbackfn": "A function that accepts up to two arguments. The some method calls the callbackfn function one time for each element in the array.",
|
||||
"Array.every|param|callbackfn": "A function that accepts up to two arguments. The every method calls the callbackfn function one time for each element in the array.",
|
||||
"Array.fill": "Fills all the elements of an array from a start index to an end index with a static value. The end index is not included.",
|
||||
"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.find": "Returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.",
|
||||
"Array.forEach": "Call a defined callback function on each element of an array.",
|
||||
"Array.forEach|param|callbackfn": "A function that accepts up to two arguments. The forEach method calls the callbackfn function one time for each element in the array.",
|
||||
"Array.get": "Get the value at a particular index.",
|
||||
"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, increase the array length by 1.",
|
||||
"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.insertAt|param|value": "to insert, eg: 0",
|
||||
"Array.isArray": "Check if a given object is an array.",
|
||||
"Array.join": "joins all elements of an array into a string and returns this string.",
|
||||
"Array.join|param|sep": "the string separator",
|
||||
"Array.length": "Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.",
|
||||
"Array.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 elements to an array.",
|
||||
"Array.push|param|item": "to append to the Array.",
|
||||
"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.removeAt|param|index": "the zero-based position in the list to remove the value from, eg: 0",
|
||||
"Array.removeElement": "Remove the first occurence of an object. Return true if removed.",
|
||||
"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": "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.",
|
||||
@ -46,21 +48,27 @@
|
||||
"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.",
|
||||
"Array.unshift|param|value": "to insert at the start of the Array.",
|
||||
"Array@type": "Add, remove, and replace items in lists.",
|
||||
"Boolean.toString": "Returns a string representation of an object.",
|
||||
"Buffer.concat": "Return concatenation of current buffer and the given buffer",
|
||||
"Buffer.fill": "Fill (a fragment) of the buffer with given value.",
|
||||
"Buffer.getNumber": "Read a number in specified format from the buffer.",
|
||||
"Buffer.getUint8": "Reads an unsigned byte at a particular location",
|
||||
"Buffer.indexOf": "Return position of other buffer in current buffer",
|
||||
"Buffer.length": "Returns the length of a Buffer object.",
|
||||
"Buffer.rotate": "Rotate buffer left in place.",
|
||||
"Buffer.rotate|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1",
|
||||
"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.",
|
||||
"Buffer.shift|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1",
|
||||
"Buffer.setUint8": "Writes an unsigned byte at a particular location",
|
||||
"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.toString": "Convert a buffer to string assuming UTF8 encoding",
|
||||
"Buffer.write": "Write contents of `src` at `dstOffset` in current buffer.",
|
||||
"Colors": "Well known colors",
|
||||
"EventCreationMode": "How to create the event.",
|
||||
@ -81,8 +89,8 @@
|
||||
"Image.height": "Gets the height in rows (always 5)",
|
||||
"Image.pixel": "Get the pixel state at position ``(x,y)``",
|
||||
"Image.pixelBrightness": "Gets the pixel brightness ([0..255]) at a given position",
|
||||
"Image.pixel|param|x": "TODO",
|
||||
"Image.pixel|param|y": "TODO",
|
||||
"Image.pixel|param|x": "pixel column",
|
||||
"Image.pixel|param|y": "pixel row",
|
||||
"Image.plotFrame": "Draws the ``index``-th frame of the image on the screen.",
|
||||
"Image.plotFrame|param|xOffset": "column index to start displaying the image",
|
||||
"Image.plotImage": "Plots the image at a given column to the screen",
|
||||
@ -91,59 +99,112 @@
|
||||
"Image.scrollImage|param|interval": "time between each animation step in milli seconds, eg: 200",
|
||||
"Image.setPixel": "Set a pixel state at position ``(x,y)``",
|
||||
"Image.setPixelBrightness": "Sets a specific pixel brightness at a given position",
|
||||
"Image.setPixel|param|value": "TODO",
|
||||
"Image.setPixel|param|x": "TODO",
|
||||
"Image.setPixel|param|y": "TODO",
|
||||
"Image.showFrame": "Shows a particular frame of the image strip.",
|
||||
"Image.showFrame|param|frame": "TODO",
|
||||
"Image.setPixel|param|value": "pixel state",
|
||||
"Image.setPixel|param|x": "pixel column",
|
||||
"Image.setPixel|param|y": "pixel row",
|
||||
"Image.showFrame": "Show a particular frame of the image strip.",
|
||||
"Image.showFrame|param|frame": "image frame to show",
|
||||
"Image.showImage": "Shows an frame from the image at offset ``x offset``.",
|
||||
"Image.showImage|param|xOffset": "column index to start displaying the image",
|
||||
"Image.width": "Gets the width in columns",
|
||||
"Infinity": "Constant representing positive infinity.",
|
||||
"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",
|
||||
"Math.acos|param|x": "A number",
|
||||
"Math.asin": "Returns the arcsine (in radians) of a number",
|
||||
"Math.asin|param|x": "A number",
|
||||
"Math.atan": "Returns the arctangent (in radians) of a number",
|
||||
"Math.atan2": "Returns the arctangent of the quotient of its arguments.",
|
||||
"Math.atan2|param|x": "A number",
|
||||
"Math.atan2|param|y": "A number",
|
||||
"Math.atan|param|x": "A number",
|
||||
"Math.ceil": "Returns the smallest number greater than or equal to its numeric argument.",
|
||||
"Math.ceil|param|x": "A numeric expression.",
|
||||
"Math.constrain": "Constrains a number to be within a range",
|
||||
"Math.cos": "Returns the cosine of a number.",
|
||||
"Math.cos|param|x": "An angle in radians",
|
||||
"Math.exp": "Returns returns ``e^x``.",
|
||||
"Math.exp|param|x": "A number",
|
||||
"Math.floor": "Returns the greatest number less than or equal to its numeric argument.",
|
||||
"Math.floor|param|x": "A numeric expression.",
|
||||
"Math.icos": "Returns the cosine of an input angle. This is an 8-bit approximation.",
|
||||
"Math.icos|param|theta": "input angle from 0-255",
|
||||
"Math.idiv": "Returns the value of integer signed 32 bit division of two numbers.",
|
||||
"Math.idiv|param|x": "The first number",
|
||||
"Math.idiv|param|y": "The second number",
|
||||
"Math.imul": "Returns the value of integer signed 32 bit multiplication of two numbers.",
|
||||
"Math.imul|param|x": "The first number",
|
||||
"Math.imul|param|y": "The second number",
|
||||
"Math.isin": "Returns the sine of an input angle. This is an 8-bit approximation.",
|
||||
"Math.isin|param|theta": "input angle from 0-255",
|
||||
"Math.log": "Returns the natural logarithm (base e) of a number.",
|
||||
"Math.log|param|x": "A number",
|
||||
"Math.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.",
|
||||
"Math.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023",
|
||||
"Math.map|param|fromLow": "the lower bound of the value's current range",
|
||||
"Math.map|param|toHigh": "the upper bound of the value's target range, eg: 4",
|
||||
"Math.map|param|toLow": "the lower bound of the value's target range",
|
||||
"Math.map|param|value": "value to map in ranges",
|
||||
"Math.max": "Returns the larger of two supplied numeric expressions.",
|
||||
"Math.min": "Returns the smaller of two supplied numeric expressions.",
|
||||
"Math.pow": "Return the value of a base expression taken to a specified power.",
|
||||
"Math.pow": "Returns the value of a base expression taken to a specified power.",
|
||||
"Math.pow|param|x": "The base value of the expression.",
|
||||
"Math.pow|param|y": "The exponent value of the expression.",
|
||||
"Math.random": "Return a pseudorandom number between 0 and `limit`.",
|
||||
"Math.random": "Returns a pseudorandom number between 0 and 1.",
|
||||
"Math.randomBoolean": "Generates a `true` or `false` value randomly, just like flipping a coin.",
|
||||
"Math.random|param|limit": "the upper bound of the number generated, eg: 4",
|
||||
"Math.randomRange": "Returns a pseudorandom number between min and max included.\nIf both numbers are integral, the result is integral.",
|
||||
"Math.randomRange|param|max": "the upper inclusive bound, eg: 10",
|
||||
"Math.randomRange|param|min": "the lower inclusive bound, eg: 0",
|
||||
"Math.round": "Returns a supplied numeric expression rounded to the nearest number.",
|
||||
"Math.roundWithPrecision": "Rounds ``x`` to a number with the given number of ``digits``",
|
||||
"Math.roundWithPrecision|param|digits": "the number of resulting digits",
|
||||
"Math.roundWithPrecision|param|x": "the number to round",
|
||||
"Math.round|param|x": "The value to be rounded to the nearest number.",
|
||||
"Math.sign": "Returns the sign of the x, indicating whether x is positive, negative or zero.",
|
||||
"Math.sign|param|x": "The numeric expression to test",
|
||||
"Math.sqrt": "Return the square root of a number.",
|
||||
"Math.sin": "Returns the sine of a number.",
|
||||
"Math.sin|param|x": "An angle in radians",
|
||||
"Math.sqrt": "Returns the square root of a number.",
|
||||
"Math.sqrt|param|x": "A numeric expression.",
|
||||
"Math.tan": "Returns the tangent of a number.",
|
||||
"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.",
|
||||
"Number.toString": "Return a string representation of a number.",
|
||||
"String": "Combine, split, and search text strings.\n\nCombine, split, and search text strings.",
|
||||
"NaN": "Constant representing Not-A-Number.",
|
||||
"Number.isNaN": "Check if a given value is of type Number and it is a NaN.",
|
||||
"Number.toString": "Returns a string representation of a number.",
|
||||
"Object.keys": "Return the field names in an object.",
|
||||
"String": "Combine, 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, eg: 0",
|
||||
"String.charAt|param|index": "The zero-based index of the desired character.",
|
||||
"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": "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, eg: \"add me!\"",
|
||||
"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.includes": "Determines whether a string contains the characters of a specified string.",
|
||||
"String.includes|param|searchValue": "the text to find",
|
||||
"String.includes|param|start": "optional start index for the search",
|
||||
"String.indexOf": "Returns the position of the first occurrence of a specified value in a string.",
|
||||
"String.indexOf|param|searchValue": "the text to find",
|
||||
"String.indexOf|param|start": "optional start index for the search",
|
||||
"String.isEmpty": "Returns a value indicating if the string is empty",
|
||||
"String.length": "Return the length of a String object.",
|
||||
"String.length": "Returns the length of a String object.",
|
||||
"String.slice": "Return a substring of the current string.",
|
||||
"String.slice|param|end": "one-past-last character index",
|
||||
"String.slice|param|start": "first character index; can be negative from counting from the end, eg:0",
|
||||
"String.split": "Splits the string according to the separators",
|
||||
"String.split|param|separator": "@param limit ",
|
||||
"String.substr": "Return a substring of the current string.",
|
||||
"String.substr|param|length": "number of characters to extract, eg: 3",
|
||||
"String.substr|param|start": "first character index; can be negative from counting from the end, eg: 0",
|
||||
"String.substr|param|length": "number of characters to extract",
|
||||
"String.substr|param|start": "first character index; can be negative from counting from the end, eg:0",
|
||||
"String.toLowerCase": "Converts the string to lower case characters.",
|
||||
"String@type": "Combine, split, and search text strings.",
|
||||
"StringMap": "A dictionary from string key to string values",
|
||||
"basic": "Provides access to basic micro:bit functionality.\n\nProvides access to basic micro:bit functionality.",
|
||||
"basic.clearScreen": "Turn off all LEDs",
|
||||
"basic.color": "Converts the color name to a number",
|
||||
@ -161,11 +222,11 @@
|
||||
"basic.showAnimation": "Shows a sequence of LED screens as an animation.",
|
||||
"basic.showAnimation|param|interval": "time in milliseconds between each redraw",
|
||||
"basic.showAnimation|param|leds": "pattern of LEDs to turn on/off",
|
||||
"basic.showArrow": "Shows an arrow on screent",
|
||||
"basic.showArrow": "Draws an arrow on the LED screen",
|
||||
"basic.showArrow|param|direction": "the direction of the arrow",
|
||||
"basic.showArrow|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.",
|
||||
"basic.showIcon": "Draws the selected icon on the LED screen",
|
||||
"basic.showIcon|param|icon": "the predifined icon id",
|
||||
"basic.showIcon|param|icon": "the predefined icon id",
|
||||
"basic.showIcon|param|interval": "the amount of time (milliseconds) to show the icon. Default is 600.",
|
||||
"basic.showLeds": "Draws an image on the LED screen.",
|
||||
"basic.showLeds|param|interval": "time in milliseconds to pause after drawing",
|
||||
@ -174,17 +235,28 @@
|
||||
"basic.showNumber|param|interval": "speed of scroll; eg: 150, 100, 200, -100",
|
||||
"basic.showString": "Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.",
|
||||
"basic.showString|param|interval": "how fast to shift characters; eg: 150, 100, 200, -100",
|
||||
"basic.showString|param|text": "the text to scroll on the screen, eg: \"Hello!\"",
|
||||
"basic.showString|param|text": "the text to scroll on the screen, eg: \"hi!\"",
|
||||
"basic.turnRgbLedOff": "Sets the color on the build-in LED. Set to 0 to turn off.",
|
||||
"console": "Reading and writing data to the console output.",
|
||||
"console.addListener": "Adds a listener for the log messages",
|
||||
"console.log": "Write a line of text to the console output.",
|
||||
"console.logValue": "Write a name:value pair as a line of text to the console output.",
|
||||
"console.logValue|param|name": "name of the value stream, eg: \"x\"",
|
||||
"console.logValue|param|value": "to write",
|
||||
"control": "Runtime and event utilities.",
|
||||
"control.assert": "If the condition is false, display msg on serial console, and panic with code 098.",
|
||||
"control.deviceName": "Gets a friendly name for the device derived from the its serial number",
|
||||
"control.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"control.createBufferFromUTF8": "Create a new buffer with UTF8-encoded string",
|
||||
"control.createBufferFromUTF8|param|str": "the string to put in the buffer",
|
||||
"control.createBuffer|param|size": "number of bytes in the buffer",
|
||||
"control.deviceName": "Make a friendly name for the device based on its serial number",
|
||||
"control.deviceSerialNumber": "Derive a unique, consistent serial number of this device from internal data.",
|
||||
"control.eventSourceId": "Returns the value of a C++ runtime constant",
|
||||
"control.eventTimestamp": "Gets the timestamp of the last event executed on the bus",
|
||||
"control.eventValue": "Gets the value of the last event executed on the bus",
|
||||
"control.eventValueId": "Returns the value of a C++ runtime constant",
|
||||
"control.inBackground": "Schedules code that run in the background.",
|
||||
"control.onEvent": "Raises an event in the event bus.",
|
||||
"control.onEvent": "Registers an event handler.",
|
||||
"control.panic": "Display specified error code and stop the program.",
|
||||
"control.raiseEvent": "Raises an event in the event bus.",
|
||||
"control.raiseEvent|param|mode": "optional definition of how the event should be processed after construction (default is CREATE_AND_FIRE).",
|
||||
@ -194,6 +266,8 @@
|
||||
"control.runtimeWarning": "Display warning in the simulator.",
|
||||
"control.waitMicros": "Blocks the current fiber for the given microseconds",
|
||||
"control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4",
|
||||
"convertToText": "Convert any value to text",
|
||||
"convertToText|param|value": "value to be converted to text",
|
||||
"game": "A single-LED sprite game engine",
|
||||
"game.LedSprite": "A game sprite rendered as a single LED",
|
||||
"game.LedSprite.blink": "Reports the ``blink`` duration of a sprite",
|
||||
@ -219,9 +293,10 @@
|
||||
"game.LedSprite.goTo|param|x": "TODO",
|
||||
"game.LedSprite.goTo|param|y": "TODO",
|
||||
"game.LedSprite.ifOnEdgeBounce": "If touching the edge of the stage and facing towards it, then turn away.",
|
||||
"game.LedSprite.isDeleted": "Reports whether the sprite has been deleted from the game engine.",
|
||||
"game.LedSprite.isTouching": "Reports true if sprite has the same position as specified sprite",
|
||||
"game.LedSprite.isTouchingEdge": "Reports true if sprite is touching an edge",
|
||||
"game.LedSprite.isTouching|param|other": "TODO",
|
||||
"game.LedSprite.isTouching|param|other": "the other sprite to check overlap or touch",
|
||||
"game.LedSprite.move": "Move a certain number of LEDs in the current direction",
|
||||
"game.LedSprite.move|param|leds": "number of leds to move, eg: 1, -1",
|
||||
"game.LedSprite.off": "Turns off the sprite (on by default)",
|
||||
@ -232,7 +307,7 @@
|
||||
"game.LedSprite.setBrightness": "Set the ``brightness`` of a sprite",
|
||||
"game.LedSprite.setBrightness|param|brightness": "the brightness from 0 (off) to 255 (on), eg: 255.",
|
||||
"game.LedSprite.setDirection": "Set the direction of the current sprite, rounded to the nearest multiple of 45",
|
||||
"game.LedSprite.setDirection|param|degrees": "TODO",
|
||||
"game.LedSprite.setDirection|param|degrees": "new direction in degrees",
|
||||
"game.LedSprite.setX": "Set the ``x`` position of a sprite",
|
||||
"game.LedSprite.setX|param|x": "TODO",
|
||||
"game.LedSprite.setY": "Set the ``y`` position of a sprite",
|
||||
@ -247,8 +322,8 @@
|
||||
"game.LedSprite.turn|param|direction": "left or right",
|
||||
"game.LedSprite.x": "Reports the ``x`` position of a sprite on the LED screen",
|
||||
"game.LedSprite.y": "Reports the ``y`` position of a sprite on the LED screen",
|
||||
"game.addLife": "Adds life points to the current life",
|
||||
"game.addLife|param|lives": "TODO",
|
||||
"game.addLife": "Add life points to the current life amount",
|
||||
"game.addLife|param|lives": "amount of lives to add",
|
||||
"game.addScore": "Adds points to the current score and shows an animation",
|
||||
"game.addScore|param|points": "amount of points to change, eg: 1",
|
||||
"game.createSprite": "Creates a new LED sprite pointing to the right.",
|
||||
@ -257,38 +332,42 @@
|
||||
"game.currentTime": "Gets the remaining time (since `start countdown`) or current time (since the device started or `start stopwatch`) in milliseconds.",
|
||||
"game.gameOver": "Displays a game over animation and the score.",
|
||||
"game.invalidSprite": "Gets an invalid sprite; used to initialize locals.",
|
||||
"game.isGameOver": "Indicates if the game is display the game over sequence.",
|
||||
"game.isGameOver": "Indicates if the game is over and displaying the game over sequence.",
|
||||
"game.isPaused": "Indicates if the game rendering is paused to allow other animations",
|
||||
"game.isRunning": "Gets a value indicating if the game is still running. Returns `false` if game over.",
|
||||
"game.isRunning": "Indicates if the game is still running. Returns `false` if the game is over or paused.",
|
||||
"game.level": "Gets the current level",
|
||||
"game.levelUp": "Increments the level and display a message.",
|
||||
"game.life": "Gets the current life",
|
||||
"game.pause": "Pauses the game rendering engine to allow other animations",
|
||||
"game.removeLife": "Removes some life",
|
||||
"game.removeLife|param|life": "TODO",
|
||||
"game.removeLife": "Remove some life",
|
||||
"game.removeLife|param|life": "amount of life to remove",
|
||||
"game.resume": "Resumes the game rendering engine",
|
||||
"game.score": "Gets the current score",
|
||||
"game.setLife": "Sets the current life value",
|
||||
"game.setLife|param|value": "TODO",
|
||||
"game.setLife|param|value": "current life value",
|
||||
"game.setScore": "Sets the current score value",
|
||||
"game.setScore|param|value": "new score value.",
|
||||
"game.showScore": "Displays the score on the screen.",
|
||||
"game.startCountdown": "Shows an animation, then starts a game countdown timer, which causes Game Over when it reaches 0",
|
||||
"game.startCountdown|param|ms": "countdown duration in milliseconds, eg: 10000",
|
||||
"game.startStopwatch": "Starts a stopwatch timer. `current time` will return the elapsed time.",
|
||||
"hex": "Tagged hex literal converter",
|
||||
"images": "Creation, manipulation and display of LED images.",
|
||||
"images.createBigImage": "Creates an image with 2 frames.",
|
||||
"images.createImage": "Creates an image that fits on the LED screen.",
|
||||
"input": "Events and data from sensors",
|
||||
"input.acceleration": "Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)",
|
||||
"input.acceleration|param|dimension": "TODO",
|
||||
"input.acceleration|param|dimension": "x, y, or z dimension, eg: Dimension.X",
|
||||
"input.buttonIsPressed": "Get the button state (pressed or not) for ``A`` and ``B``.",
|
||||
"input.buttonIsPressed|param|button": "the button to query the request, eg: Button.A",
|
||||
"input.calibrate": "Obsolete, use input.calibrateCompass instead.",
|
||||
"input.calibrateCompass": "Obsolete, compass calibration is automatic.",
|
||||
"input.compassHeading": "Get the current compass heading in degrees.",
|
||||
"input.isGesture": "Tests if a gesture is currently detected.",
|
||||
"input.isGesture|param|gesture": "the type of gesture to detect, eg: Gesture.Shake",
|
||||
"input.lightLevel": "Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.",
|
||||
"input.magneticForce": "Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.",
|
||||
"input.magneticForce|param|dimension": "TODO",
|
||||
"input.magneticForce|param|dimension": "the x, y, or z dimension, eg: Dimension.X",
|
||||
"input.onButtonPressed": "Do something when a button (A, B or both A+B) is pushed down and released again.",
|
||||
"input.onButtonPressed|param|body": "code to run when event is raised",
|
||||
"input.onButtonPressed|param|button": "the button that needs to be pressed",
|
||||
@ -314,7 +393,7 @@
|
||||
"input.pinIsPressed": "Get the pin state (pressed or not). Requires to hold the ground to close the circuit.",
|
||||
"input.pinIsPressed|param|name": "pin used to detect the touch, eg: TouchPin.P0",
|
||||
"input.rotation": "The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees.",
|
||||
"input.rotation|param|kind": "TODO",
|
||||
"input.rotation|param|kind": "pitch or roll",
|
||||
"input.runningTime": "Gets the number of milliseconds elapsed since power on.",
|
||||
"input.runningTimeMicros": "Gets the number of microseconds elapsed since power on.",
|
||||
"input.setAccelerometerRange": "Sets the accelerometer sample range in gravities.",
|
||||
@ -325,9 +404,9 @@
|
||||
"led.displayMode": "Gets the current display mode",
|
||||
"led.enable": "Turns on or off the display",
|
||||
"led.fadeIn": "Fades in the screen display.",
|
||||
"led.fadeIn|param|ms": "TODO",
|
||||
"led.fadeIn|param|ms": "fade time in milleseconds",
|
||||
"led.fadeOut": "Fades out the screen brightness.",
|
||||
"led.fadeOut|param|ms": "TODO",
|
||||
"led.fadeOut|param|ms": "fade time in milliseconds",
|
||||
"led.plot": "Turn on the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.",
|
||||
"led.plotAll": "Turns all LEDS on",
|
||||
"led.plotBarGraph": "Displays a vertical bar graph based on the `value` and `high` value.\nIf `high` is 0, the chart gets adjusted automatically.",
|
||||
@ -340,8 +419,8 @@
|
||||
"led.plot|param|x": "the horizontal coordinate of the LED starting at 0",
|
||||
"led.plot|param|y": "the vertical coordinate of the LED starting at 0",
|
||||
"led.point": "Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.",
|
||||
"led.point|param|x": "TODO",
|
||||
"led.point|param|y": "TODO",
|
||||
"led.point|param|x": "the horizontal coordinate of the LED",
|
||||
"led.point|param|y": "the vertical coordinate of the LED",
|
||||
"led.screenshot": "Takes a screenshot of the LED screen and returns an image.",
|
||||
"led.setBrightness": "Set the screen brightness from 0 (off) to 255 (full bright).",
|
||||
"led.setBrightness|param|value": "the brightness value, eg:255, 127, 0",
|
||||
@ -350,57 +429,65 @@
|
||||
"led.stopAnimation": "Cancels the current animation and clears other pending animations.",
|
||||
"led.toggle": "Toggles a particular pixel",
|
||||
"led.toggleAll": "Inverts the current LED display",
|
||||
"led.toggle|param|x": "TODO",
|
||||
"led.toggle|param|y": "TODO",
|
||||
"led.toggle|param|x": "pixel column",
|
||||
"led.toggle|param|y": "pixel row",
|
||||
"led.unplot": "Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.",
|
||||
"led.unplot|param|x": "TODO",
|
||||
"led.unplot|param|y": "TODO",
|
||||
"led.unplot|param|x": "the horizontal coordinate of the LED",
|
||||
"led.unplot|param|y": "the vertical coordinate of the LED",
|
||||
"motors": "Blocks to control the onboard motors",
|
||||
"motors.dualMotorPower": "Controls two motors attached to the board. Switches to dual-motor mode!",
|
||||
"motors.motorCommand": "Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.",
|
||||
"motors.motorPower": "Turns on the motor at a certain percent of power. Switches to single motor mode!",
|
||||
"motors.motorPower|param|power": "%percent of power sent to the motor. Negative power goes backward. eg: 50",
|
||||
"msgpack.packNumberArray": "Pack a number array into a buffer.",
|
||||
"msgpack.packNumberArray|param|nums": "the numbers to be packed",
|
||||
"msgpack.unpackNumberArray": "Unpacks a buffer into a number array.",
|
||||
"music": "Generation of music tones.",
|
||||
"music.beat": "Returns the duration of a beat in milli-seconds",
|
||||
"music.beginMelody": "Starts playing a melody.\nNotes are expressed as a string of characters with this format: NOTE[octave][:duration]",
|
||||
"music.beginMelody|param|melodyArray": "the melody array to play, eg: ['g5:1']",
|
||||
"music.beginMelody|param|melodyArray": "the melody array to play",
|
||||
"music.beginMelody|param|options": "melody options, once / forever, in the foreground / background",
|
||||
"music.builtInMelody": "Gets the melody array of a built-in melody.",
|
||||
"music.changeTempoBy": "Change the tempo by the specified amount",
|
||||
"music.changeTempoBy|param|bpm": "The change in beats per minute to the tempo, eg: 20",
|
||||
"music.noteFrequency": "Gets the frequency of a note.",
|
||||
"music.noteFrequency": "Get the frequency of a note.",
|
||||
"music.noteFrequency|param|name": "the note name, eg: Note.C",
|
||||
"music.onEvent": "Registers code to run on various melody events",
|
||||
"music.playTone": "Plays a tone through pin ``P0`` for the given duration.",
|
||||
"music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
|
||||
"music.playTone|param|frequency": "pitch of the tone to play in Hertz (Hz), eg: Note.C",
|
||||
"music.playTone|param|ms": "tone duration in milliseconds (ms)",
|
||||
"music.rest": "Rests (plays nothing) for a specified time through pin ``P0``.",
|
||||
"music.rest|param|ms": "rest duration in milliseconds (ms)",
|
||||
"music.ringTone": "Plays a tone through pin ``P0``.",
|
||||
"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.setPlayTone": "Sets a custom playTone function for playing melodies",
|
||||
"music.setTempo": "Sets the tempo to the specified amount",
|
||||
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
|
||||
"music.speakerPlayTone": "Plays a tone through ``speaker`` for the given duration.",
|
||||
"music.speakerPlayTone|param|frequency": "pitch of the tone to play in Hertz (Hz)",
|
||||
"music.speakerPlayTone|param|ms": "tone duration in milliseconds (ms)",
|
||||
"music.stopMelody": "Stops the melodies",
|
||||
"music.stopMelody|param|options": "which melody to stop",
|
||||
"music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.",
|
||||
"parseFloat": "Convert a string to a number.",
|
||||
"parseInt": "Convert a string to an integer.",
|
||||
"pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...",
|
||||
"pins.analogPitch": "Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.",
|
||||
"pins.analogPitch": "Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.",
|
||||
"pins.analogPitch|param|frequency": "frequency to modulate in Hz.",
|
||||
"pins.analogPitch|param|ms": "duration of the pitch in milli seconds.",
|
||||
"pins.analogReadPin": "Read the connector value as analog, that is, as a value comprised between 0 and 1023.",
|
||||
"pins.analogReadPin|param|name": "pin to write to, eg: AnalogPin.P0",
|
||||
"pins.analogSetPeriod": "Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.",
|
||||
"pins.analogSetPeriod": "Configure the pulse-width modulation (PWM) period of the analog output in microseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.",
|
||||
"pins.analogSetPeriod|param|micros": "period in micro seconds. eg:20000",
|
||||
"pins.analogSetPeriod|param|name": "analog pin to set period to, eg: AnalogPin.P0",
|
||||
"pins.analogSetPitchPin": "Sets the pin used when using `analog pitch` or music.",
|
||||
"pins.analogSetPitchPin": "Set the pin used when using analog pitch or music.",
|
||||
"pins.analogSetPitchPin|param|name": "pin to modulate pitch from",
|
||||
"pins.analogWritePin": "Set the connector value as analog. Value must be comprised between 0 and 1023.",
|
||||
"pins.analogWritePin|param|name": "pin name to write to, eg: AnalogPin.P0",
|
||||
"pins.analogWritePin|param|value": "value to write to the pin between ``0`` and ``1023``. eg:1023,0",
|
||||
"pins.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"pins.createBufferFromArray": "Create a new buffer initalized to bytes from given array.",
|
||||
"pins.createBufferFromArray|param|bytes": "data to initalize with",
|
||||
"pins.createBuffer|param|size": "number of bytes in the buffer",
|
||||
"pins.digitalReadPin": "Read the specified pin or connector as either 0 or 1",
|
||||
"pins.digitalReadPin|param|name": "pin to read from, eg: DigitalPin.P0",
|
||||
@ -411,56 +498,68 @@
|
||||
"pins.i2cReadNumber": "Read one number from 7-bit I2C address.",
|
||||
"pins.i2cWriteBuffer": "Write bytes to a 7-bit I2C `address`.",
|
||||
"pins.i2cWriteNumber": "Write one number to a 7-bit I2C address.",
|
||||
"pins.map": "Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.",
|
||||
"pins.map": "Map a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.",
|
||||
"pins.map|param|fromHigh": "the upper bound of the value's current range, eg: 1023",
|
||||
"pins.map|param|fromLow": "the lower bound of the value's current range",
|
||||
"pins.map|param|toHigh": "the upper bound of the value's target range, eg: 4",
|
||||
"pins.map|param|toLow": "the lower bound of the value's target range",
|
||||
"pins.map|param|value": "value to map in ranges",
|
||||
"pins.onPulsed": "Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``.",
|
||||
"pins.onPulsed": "Configure the pin as a digital input and generate an event when the pin is pulsed either high or low.",
|
||||
"pins.onPulsed|param|name": "digital pin to register to, eg: DigitalPin.P0",
|
||||
"pins.onPulsed|param|pulse": "the value of the pulse, eg: PulseValue.High",
|
||||
"pins.pulseDuration": "Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler.",
|
||||
"pins.pulseIn": "Returns the duration of a pulse in microseconds",
|
||||
"pins.pulseDuration": "Get the duration of the last pulse in microseconds. This function should be called from a ``onPulsed`` handler.",
|
||||
"pins.pulseIn": "Return the duration of a pulse at a pin in microseconds.",
|
||||
"pins.pulseIn|param|name": "the pin which measures the pulse, eg: DigitalPin.P0",
|
||||
"pins.pulseIn|param|value": "the value of the pulse, eg: PulseValue.High",
|
||||
"pins.servoSetPulse": "Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.",
|
||||
"pins.servoSetPulse": "Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds.",
|
||||
"pins.servoSetPulse|param|micros": "pulse duration in micro seconds, eg:1500",
|
||||
"pins.servoSetPulse|param|name": "pin name",
|
||||
"pins.servoWritePin": "Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).",
|
||||
"pins.servoWritePin": "Write a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).",
|
||||
"pins.servoWritePin|param|name": "pin to write to, eg: AnalogPin.P0",
|
||||
"pins.servoWritePin|param|value": "angle or rotation speed, eg:180,90,0",
|
||||
"pins.setEvents": "Configures the events emitted by this pin. Events can be subscribed to\nusing ``control.onEvent()``.",
|
||||
"pins.setEvents": "Configure the events emitted by this pin. Events can be subscribed to\nusing ``control.onEvent()``.",
|
||||
"pins.setEvents|param|name": "pin to set the event mode on, eg: DigitalPin.P0",
|
||||
"pins.setEvents|param|type": "the type of events for this pin to emit, eg: PinEventType.Edge",
|
||||
"pins.setPull": "Configures the pull of this pin.",
|
||||
"pins.setPull": "Configure the pull directiion of of a pin.",
|
||||
"pins.setPull|param|name": "pin to set the pull mode on, eg: DigitalPin.P0",
|
||||
"pins.setPull|param|pull": "one of the mbed pull configurations, eg: PinPullMode.PullUp",
|
||||
"pins.sizeOf": "Get the size in bytes of specified number format.",
|
||||
"pins.spiFormat": "Sets the SPI bits and mode",
|
||||
"pins.spiFormat": "Set the SPI bits and mode",
|
||||
"pins.spiFormat|param|bits": "the number of bits, eg: 8",
|
||||
"pins.spiFormat|param|mode": "the mode, eg: 3",
|
||||
"pins.spiFrequency": "Sets the SPI frequency",
|
||||
"pins.spiFrequency": "Set the SPI frequency",
|
||||
"pins.spiFrequency|param|frequency": "the clock frequency, eg: 1000000",
|
||||
"pins.spiPins": "Sets the MOSI, MISO, SCK pins used by the SPI instance",
|
||||
"pins.spiPins": "Set the MOSI, MISO, SCK pins used by the SPI connection",
|
||||
"pins.spiWrite": "Write to the SPI slave and return the response",
|
||||
"pins.spiWrite|param|value": "Data to be sent to the SPI slave",
|
||||
"serial": "Reading and writing data over a serial connection.",
|
||||
"serial.delimiters": "Returns the delimiter corresponding string",
|
||||
"serial.onDataReceived": "Registers an event to be fired when one of the delimiter is matched.",
|
||||
"serial.NEW_LINE": "The string used to mark a new line, default is \\r\\n",
|
||||
"serial.delimiters": "Return the corresponding delimiter string",
|
||||
"serial.onDataReceived": "Register an event to be fired when one of the delimiter is matched.",
|
||||
"serial.onDataReceived|param|delimiters": "the characters to match received characters against.",
|
||||
"serial.readLine": "Reads a line of text from the serial port.",
|
||||
"serial.readString": "Reads the buffered received data as a string",
|
||||
"serial.readUntil": "Reads a line of text from the serial port and returns the buffer when the delimiter is met.",
|
||||
"serial.readBuffer": "Read multiple characters from the receive buffer. Pause until enough characters are present.",
|
||||
"serial.readBuffer|param|length": "default buffer length, eg: 64",
|
||||
"serial.readLine": "Read a line of text from the serial port.",
|
||||
"serial.readString": "Read the buffered received data as a string",
|
||||
"serial.readUntil": "Read a line of text from the serial port and return the buffer when the delimiter is met.",
|
||||
"serial.readUntil|param|delimiter": "text delimiter that separates each text chunk",
|
||||
"serial.redirect": "Dynamically configuring the serial instance to use pins other than USBTX and USBRX.",
|
||||
"serial.redirect": "Set the serial input and output to use pins instead of the USB connection.",
|
||||
"serial.redirectToUSB": "Direct the serial input and output to use the USB connection.",
|
||||
"serial.redirect|param|rate": "the new baud rate. eg: 115200",
|
||||
"serial.redirect|param|rx": "the new reception pin, eg: SerialPin.P1",
|
||||
"serial.redirect|param|tx": "the new transmission pins, eg: SerialPin.P0",
|
||||
"serial.writeLine": "Prints a line of text to the serial",
|
||||
"serial.writeNumber": "Prints a numeric value to the serial",
|
||||
"serial.writeString": "Sends a piece of text through Serial connection.",
|
||||
"serial.writeValue": "Writes a ``name: value`` pair line to the serial.",
|
||||
"serial.redirect|param|tx": "the new transmission pin, eg: SerialPin.P0",
|
||||
"serial.setRxBufferSize": "Sets the size of the RX buffer in bytes",
|
||||
"serial.setRxBufferSize|param|size": "length of the rx buffer in bytes, eg: 32",
|
||||
"serial.setTxBufferSize": "Sets the size of the TX buffer in bytes",
|
||||
"serial.setTxBufferSize|param|size": "length of the tx buffer in bytes, eg: 32",
|
||||
"serial.setWriteLinePadding": "Sets the padding length for lines sent with \"write line\".",
|
||||
"serial.setWriteLinePadding|param|length": "the number of bytes alignment, eg: 0",
|
||||
"serial.writeBuffer": "Send a buffer through serial connection",
|
||||
"serial.writeLine": "Print a line of text to the serial port",
|
||||
"serial.writeNumber": "Print a numeric value to the serial port",
|
||||
"serial.writeNumbers": "Print an array of numeric values as CSV to the serial port",
|
||||
"serial.writeString": "Send a piece of text through the serial connection.",
|
||||
"serial.writeValue": "Write a name:value pair as a line to the serial port.",
|
||||
"serial.writeValue|param|name": "name of the value stream, eg: x",
|
||||
"serial.writeValue|param|value": "to write"
|
||||
}
|
@ -26,7 +26,15 @@
|
||||
"ArrowNames.South|block": "South",
|
||||
"ArrowNames.West|block": "West",
|
||||
"BaudRate.BaudRate115200|block": "115200",
|
||||
"BaudRate.BaudRate56700|block": "57600",
|
||||
"BaudRate.BaudRate1200|block": "1200",
|
||||
"BaudRate.BaudRate14400|block": "14400",
|
||||
"BaudRate.BaudRate19200|block": "19200",
|
||||
"BaudRate.BaudRate2400|block": "2400",
|
||||
"BaudRate.BaudRate28800|block": "28800",
|
||||
"BaudRate.BaudRate31250|block": "31250",
|
||||
"BaudRate.BaudRate38400|block": "38400",
|
||||
"BaudRate.BaudRate4800|block": "4800",
|
||||
"BaudRate.BaudRate57600|block": "57600",
|
||||
"BaudRate.BaudRate9600|block": "9600",
|
||||
"BeatFraction.Breve|block": "4",
|
||||
"BeatFraction.Double|block": "2",
|
||||
@ -39,6 +47,7 @@
|
||||
"Colors.Blue|block": "blue",
|
||||
"Colors.Green|block": "green",
|
||||
"Colors.Indigo|block": "indigo",
|
||||
"Colors.Off|block": "off",
|
||||
"Colors.Orange|block": "orange",
|
||||
"Colors.Purple|block": "purple",
|
||||
"Colors.Red|block": "red",
|
||||
@ -57,7 +66,7 @@
|
||||
"Dimension.Z|block": "z",
|
||||
"Direction.Left|block": "left",
|
||||
"Direction.Right|block": "right",
|
||||
"DisplayMode.BackAndWhite|block": "black and white",
|
||||
"DisplayMode.BlackAndWhite|block": "black and white",
|
||||
"DisplayMode.Greyscale|block": "greyscale",
|
||||
"EventCreationMode.CreateAndFire": "MicroBitEvent is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!).",
|
||||
"EventCreationMode.CreateOnly": "MicroBitEvent is initialised, and no further processing takes place.",
|
||||
@ -123,15 +132,17 @@
|
||||
"IconNames.Triangle|block": "triangle",
|
||||
"IconNames.Umbrella|block": "umbrella",
|
||||
"IconNames.Yes|block": "yes",
|
||||
"Image.scrollImage|block": "scroll image %sprite|with offset %frameoffset|and interval (ms) %delay",
|
||||
"Image.showImage|block": "show image %sprite|at offset %offset",
|
||||
"Image.scrollImage|block": "scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay",
|
||||
"Image.showImage|block": "show image %sprite(myImage)|at offset %offset",
|
||||
"LedSpriteProperty.Blink|block": "blink",
|
||||
"LedSpriteProperty.Brightness|block": "brightness",
|
||||
"LedSpriteProperty.Direction|block": "direction",
|
||||
"LedSpriteProperty.X|block": "x",
|
||||
"LedSpriteProperty.Y|block": "y",
|
||||
"Math.constrain|block": "constrain %value|between %low|and %high",
|
||||
"Math.map|block": "map %value|from low %fromLow|high %fromHigh|to low %toLow|high %toHigh",
|
||||
"Math.randomBoolean|block": "pick random true or false",
|
||||
"Math.random|block": "pick random 0 to %limit",
|
||||
"Math.randomRange|block": "pick random %min|to %limit",
|
||||
"Math|block": "Math",
|
||||
"Melodies.BaDing|block": "ba ding",
|
||||
"Melodies.Baddy|block": "baddy",
|
||||
@ -157,6 +168,9 @@
|
||||
"MelodyOptions.Forever|block": "forever",
|
||||
"MelodyOptions.OnceInBackground|block": "once in background",
|
||||
"MelodyOptions.Once|block": "once",
|
||||
"MelodyStopOptions.All|block": "all",
|
||||
"MelodyStopOptions.Background|block": "background",
|
||||
"MelodyStopOptions.Foreground|block": "foreground",
|
||||
"MesDpadButtonInfo.ADown|block": "A down",
|
||||
"MesDpadButtonInfo.AUp|block": "A up",
|
||||
"MesDpadButtonInfo.BDown|block": "B down",
|
||||
@ -199,6 +213,8 @@
|
||||
"Note.GSharp4|block": "G#4",
|
||||
"Note.GSharp5|block": "G#5",
|
||||
"Note.GSharp|block": "G#",
|
||||
"Number|block": "Number",
|
||||
"Object|block": "Object",
|
||||
"PinEventType.Edge|block": "edge",
|
||||
"PinEventType.None|block": "none",
|
||||
"PinEventType.Pulse|block": "pulse",
|
||||
@ -206,12 +222,18 @@
|
||||
"PinPullMode.PullDown|block": "down",
|
||||
"PinPullMode.PullNone|block": "none",
|
||||
"PinPullMode.PullUp|block": "up",
|
||||
"PulseValue.High|block": "high",
|
||||
"PulseValue.Low|block": "low",
|
||||
"Rotation.Pitch|block": "pitch",
|
||||
"Rotation.Roll|block": "roll",
|
||||
"String.charAt|block": "char from %this=text|at %pos",
|
||||
"String.compare|block": "compare %this=text| to %that",
|
||||
"String.fromCharCode|block": "text from char code %code",
|
||||
"String.includes|block": "%this=text|includes %searchValue",
|
||||
"String.indexOf|block": "%this=text|find index of %searchValue",
|
||||
"String.isEmpty|block": "%this=text| is empty",
|
||||
"String.length|block": "length of %VALUE",
|
||||
"String.split|block": "split %this=text|at %separator",
|
||||
"String.substr|block": "substring of %this=text|from %start|of length %length",
|
||||
"String|block": "String",
|
||||
"basic.clearScreen|block": "clear screen",
|
||||
@ -219,13 +241,15 @@
|
||||
"basic.forever|block": "forever",
|
||||
"basic.pause|block": "pause (ms) %pause",
|
||||
"basic.rgbw|block": "red %red|green %green|blue %blue|white %white",
|
||||
"basic.setLedColor|block": "set led to %color=color_id",
|
||||
"basic.setLedColor|block": "set led to %color=colorNumberPicker",
|
||||
"basic.showArrow|block": "show arrow %i=device_arrow",
|
||||
"basic.showIcon|block": "show icon %i",
|
||||
"basic.showLeds|block": "show leds",
|
||||
"basic.showNumber|block": "show|number %number",
|
||||
"basic.showString|block": "show|string %text",
|
||||
"basic.turnRgbLedOff|block": "turn build-in LED off",
|
||||
"basic|block": "basic",
|
||||
"console|block": "console",
|
||||
"control.deviceName|block": "device name",
|
||||
"control.deviceSerialNumber|block": "device serial number",
|
||||
"control.eventSourceId|block": "%id",
|
||||
@ -238,21 +262,29 @@
|
||||
"control.reset|block": "reset",
|
||||
"control.waitMicros|block": "wait (µs)%micros",
|
||||
"control|block": "control",
|
||||
"convertToText|block": "convert $value=math_number to text",
|
||||
"game.LedSprite.change|block": "%sprite|change %property|by %value",
|
||||
"game.LedSprite.delete|block": "delete %this",
|
||||
"game.LedSprite.delete|block": "delete %this(sprite)",
|
||||
"game.LedSprite.get|block": "%sprite|%property",
|
||||
"game.LedSprite.ifOnEdgeBounce|block": "%sprite|if on edge, bounce",
|
||||
"game.LedSprite.isTouchingEdge|block": "%sprite|touching edge?",
|
||||
"game.LedSprite.isTouching|block": "%sprite|touching %other|?",
|
||||
"game.LedSprite.isDeleted|block": "is %sprite|deleted",
|
||||
"game.LedSprite.isTouchingEdge|block": "is %sprite|touching edge",
|
||||
"game.LedSprite.isTouching|block": "is %sprite|touching %other",
|
||||
"game.LedSprite.move|block": "%sprite|move by %leds",
|
||||
"game.LedSprite.set|block": "%sprite|set %property|to %value",
|
||||
"game.LedSprite.turn|block": "%sprite|turn %direction|by (°) %degrees",
|
||||
"game.addLife|block": "add life %lives",
|
||||
"game.addScore|block": "change score by|%points",
|
||||
"game.createSprite|block": "create sprite at|x: %x|y: %y",
|
||||
"game.gameOver|block": "game over",
|
||||
"game.isGameOver|block": "is game over",
|
||||
"game.isPaused|block": "is paused",
|
||||
"game.isRunning|block": "is running",
|
||||
"game.pause|block": "pause",
|
||||
"game.removeLife|block": "remove life %life",
|
||||
"game.resume|block": "resume",
|
||||
"game.score|block": "score",
|
||||
"game.setLife|block": "set life %value",
|
||||
"game.setScore|block": "set score %points",
|
||||
"game.startCountdown|block": "start countdown|(ms) %duration",
|
||||
"game|block": "game",
|
||||
@ -266,6 +298,7 @@
|
||||
"input.buttonIsPressed|block": "button|%NAME|is pressed",
|
||||
"input.calibrateCompass|block": "calibrate compass",
|
||||
"input.compassHeading|block": "compass heading (°)",
|
||||
"input.isGesture|block": "is %gesture gesture",
|
||||
"input.lightLevel|block": "light level",
|
||||
"input.magneticForce|block": "magnetic force (µT)|%NAME",
|
||||
"input.onButtonPressed|block": "on button|%NAME|pressed",
|
||||
@ -281,11 +314,12 @@
|
||||
"input|block": "input",
|
||||
"led.brightness|block": "brightness",
|
||||
"led.enable|block": "led enable %on",
|
||||
"led.plotBarGraph|block": "plot bar graph of %value |up to %high",
|
||||
"led.plotBarGraph|block": "plot bar graph of %value up to %high",
|
||||
"led.plotBrightness|block": "plot|x %x|y %y|brightness %brightness",
|
||||
"led.plot|block": "plot|x %x|y %y",
|
||||
"led.point|block": "point|x %x|y %y",
|
||||
"led.setBrightness|block": "set brightness %value",
|
||||
"led.setDisplayMode|block": "set display mode $mode",
|
||||
"led.stopAnimation|block": "stop animation",
|
||||
"led.toggle|block": "toggle|x %x|y %y",
|
||||
"led.unplot|block": "unplot|x %x|y %y",
|
||||
@ -294,18 +328,21 @@
|
||||
"motors.motorCommand|block": "motor %command",
|
||||
"motors.motorPower|block": "motor on at %percent",
|
||||
"motors|block": "motors",
|
||||
"msgpack|block": "msgpack",
|
||||
"music.beat|block": "%fraction|beat",
|
||||
"music.beginMelody|block": "start melody %melody=device_builtin_melody| repeating %options",
|
||||
"music.builtInMelody|block": "%melody",
|
||||
"music.changeTempoBy|block": "change tempo by (bpm)|%value",
|
||||
"music.noteFrequency|block": "%note",
|
||||
"music.noteFrequency|block": "%name",
|
||||
"music.onEvent|block": "music on %value",
|
||||
"music.playTone|block": "play|tone %note=device_note|for %duration=device_beat",
|
||||
"music.rest|block": "rest(ms)|%duration=device_beat",
|
||||
"music.ringTone|block": "ring tone (Hz)|%note=device_note",
|
||||
"music.setTempo|block": "set tempo to (bpm)|%value",
|
||||
"music.stopMelody|block": "stop melody $options",
|
||||
"music.tempo|block": "tempo (bpm)",
|
||||
"music|block": "music",
|
||||
"parseFloat|block": "parse to number %text",
|
||||
"parseInt|block": "parse to integer %text",
|
||||
"pins.analogPitch|block": "analog pitch %frequency|for (ms) %ms",
|
||||
"pins.analogReadPin|block": "analog read|pin %name",
|
||||
@ -314,8 +351,8 @@
|
||||
"pins.analogWritePin|block": "analog write|pin %name|to %value",
|
||||
"pins.digitalReadPin|block": "digital read|pin %name",
|
||||
"pins.digitalWritePin|block": "digital write|pin %name|to %value",
|
||||
"pins.i2cReadNumber|block": "i2c read number|at address %address|of format %format=i2c_sizeof|repeat %repeat",
|
||||
"pins.i2cWriteNumber|block": "i2c write number|at address %address|with value %value|of format %format=i2c_sizeof|repeat %repeat",
|
||||
"pins.i2cReadNumber|block": "i2c read number|at address %address|of format %format|repeated %repeat",
|
||||
"pins.i2cWriteNumber|block": "i2c write number|at address %address|with value %value|of format %format|repeated %repeat",
|
||||
"pins.map|block": "map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh",
|
||||
"pins.onPulsed|block": "on|pin %pin|pulsed %pulse",
|
||||
"pins.pulseDuration|block": "pulse duration (µs)",
|
||||
@ -331,11 +368,18 @@
|
||||
"pins|block": "pins",
|
||||
"serial.delimiters|block": "%del",
|
||||
"serial.onDataReceived|block": "serial|on data received %delimiters=serial_delimiter_conv",
|
||||
"serial.readBuffer|block": "serial|read buffer %length",
|
||||
"serial.readLine|block": "serial|read line",
|
||||
"serial.readString|block": "serial|read string",
|
||||
"serial.readUntil|block": "serial|read until %delimiter=serial_delimiter_conv",
|
||||
"serial.redirectToUSB|block": "serial|redirect to USB",
|
||||
"serial.redirect|block": "serial|redirect to|TX %tx|RX %rx|at baud rate %rate",
|
||||
"serial.setRxBufferSize|block": "serial set rx buffer size to $size",
|
||||
"serial.setTxBufferSize|block": "serial set tx buffer size to $size",
|
||||
"serial.setWriteLinePadding|block": "serial set write line padding to $length",
|
||||
"serial.writeBuffer|block": "serial|write buffer %buffer=serial_readbuffer",
|
||||
"serial.writeLine|block": "serial|write line %text",
|
||||
"serial.writeNumbers|block": "serial|write numbers %values",
|
||||
"serial.writeNumber|block": "serial|write number %value",
|
||||
"serial.writeString|block": "serial|write string %text",
|
||||
"serial.writeValue|block": "serial|write value %name|= %value",
|
||||
@ -347,6 +391,8 @@
|
||||
"{id:category}Buffer": "Buffer",
|
||||
"{id:category}Console": "Console",
|
||||
"{id:category}Control": "Control",
|
||||
"{id:category}Fx": "Fx",
|
||||
"{id:category}Fx8": "Fx8",
|
||||
"{id:category}Game": "Game",
|
||||
"{id:category}Helpers": "Helpers",
|
||||
"{id:category}Image": "Image",
|
||||
@ -355,8 +401,10 @@
|
||||
"{id:category}Led": "Led",
|
||||
"{id:category}Math": "Math",
|
||||
"{id:category}Motors": "Motors",
|
||||
"{id:category}Msgpack": "Msgpack",
|
||||
"{id:category}Music": "Music",
|
||||
"{id:category}Number": "Number",
|
||||
"{id:category}Object": "Object",
|
||||
"{id:category}Pins": "Pins",
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:category}String": "String",
|
||||
|
@ -4,12 +4,13 @@
|
||||
/**
|
||||
* Provides access to basic micro:bit functionality.
|
||||
*/
|
||||
//% color=#54C9C9 weight=100 icon="\uf00a"
|
||||
//% color=#1E90FF weight=116 icon="\uf00a"
|
||||
namespace basic {
|
||||
/**
|
||||
* Sets the color on the build-in LED. Set to 0 to turn off.
|
||||
*/
|
||||
//% blockId=device_set_led_color block="set led to %color=color_id"
|
||||
//% blockId=device_set_led_color
|
||||
//% block="set led to %color=colorNumberPicker"
|
||||
//% weight=50
|
||||
void setLedColor(int color) {
|
||||
if (!color) {
|
||||
@ -25,24 +26,14 @@ namespace basic {
|
||||
uBit.rgb.setColour(r,g,b,w);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.
|
||||
* @param interval speed of scroll; eg: 150, 100, 200, -100
|
||||
*/
|
||||
//% help=basic/show-number
|
||||
//% weight=96
|
||||
//% blockId=device_show_number block="show|number %number" blockGap=8
|
||||
//% async
|
||||
//% parts="ledmatrix"
|
||||
void showNumber(int value, int interval = 150) {
|
||||
if (interval <= 0)
|
||||
interval = 1;
|
||||
ManagedString t(value);
|
||||
if (value < 0 || value >= 10) {
|
||||
uBit.display.scroll(t, interval);
|
||||
} else {
|
||||
uBit.display.printChar(t.charAt(0), interval * 5);
|
||||
}
|
||||
* Sets the color on the build-in LED. Set to 0 to turn off.
|
||||
*/
|
||||
//% blockId=device_turn_rgb_led_off block="turn build-in LED off"
|
||||
//% weight=50
|
||||
void turnRgbLedOff() {
|
||||
uBit.rgb.off();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,33 +47,33 @@ namespace basic {
|
||||
//% blockId=device_show_leds
|
||||
//% block="show leds" icon="\uf00a"
|
||||
//% parts="ledmatrix"
|
||||
void showLeds(ImageLiteral leds, int interval = 400) {
|
||||
void showLeds(ImageLiteral_ leds, int interval = 400) {
|
||||
uBit.display.print(MicroBitImage(imageBytes(leds)), 0, 0, 0, interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.
|
||||
* @param text the text to scroll on the screen, eg: "Hello!"
|
||||
* @param text the text to scroll on the screen, eg: "hi!"
|
||||
* @param interval how fast to shift characters; eg: 150, 100, 200, -100
|
||||
*/
|
||||
//% help=basic/show-string
|
||||
//% weight=87 blockGap=8
|
||||
//% weight=87 blockGap=16
|
||||
//% block="show|string %text"
|
||||
//% async
|
||||
//% blockId=device_print_message
|
||||
//% parts="ledmatrix"
|
||||
void showString(StringData *text, int interval = 150) {
|
||||
//% text.shadowOptions.toString=true
|
||||
void showString(String text, int interval = 150) {
|
||||
if (interval <= 0)
|
||||
interval = 1;
|
||||
ManagedString s(text);
|
||||
int l = s.length();
|
||||
int l = text ? text->getUTF8Size() : 0;
|
||||
if (l == 0) {
|
||||
uBit.display.clear();
|
||||
fiber_sleep(interval * 5);
|
||||
} else if (l > 1) {
|
||||
uBit.display.scroll(s, interval);
|
||||
uBit.display.scroll(MSTR(text), interval);
|
||||
} else {
|
||||
uBit.display.print(s.charAt(0), interval * 5);
|
||||
uBit.display.printChar(text->getUTF8Data()[0], interval * 5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +95,7 @@ namespace basic {
|
||||
*/
|
||||
//% help=basic/show-animation imageLiteral=1 async
|
||||
//% parts="ledmatrix"
|
||||
void showAnimation(ImageLiteral leds, int interval = 400) {
|
||||
void showAnimation(ImageLiteral_ leds, int interval = 400) {
|
||||
uBit.display.animate(MicroBitImage(imageBytes(leds)), interval, 5, 0, 0);
|
||||
}
|
||||
|
||||
@ -114,29 +105,19 @@ namespace basic {
|
||||
*/
|
||||
//% help=basic/plot-leds weight=80
|
||||
//% parts="ledmatrix"
|
||||
void plotLeds(ImageLiteral leds) {
|
||||
void plotLeds(ImageLiteral_ leds) {
|
||||
MicroBitImage i(imageBytes(leds));
|
||||
uBit.display.print(i, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void forever_stub(void *a) {
|
||||
while (true) {
|
||||
runAction0((Action)a);
|
||||
fiber_sleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeats the code forever in the background. On each iteration, allows other codes to run.
|
||||
* @param body code to execute
|
||||
*/
|
||||
//% help=basic/forever weight=55 blockGap=8 blockAllowMultiple=1 afterOnStart=true
|
||||
//% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true
|
||||
//% blockId=device_forever block="forever" icon="\uf01e"
|
||||
void forever(Action a) {
|
||||
if (a != 0) {
|
||||
incr(a);
|
||||
create_fiber(forever_stub, (void*)a);
|
||||
}
|
||||
runForever(a);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,8 +125,9 @@ namespace basic {
|
||||
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
|
||||
*/
|
||||
//% help=basic/pause weight=54
|
||||
//% async block="pause (ms) %pause"
|
||||
//% async block="pause (ms) %pause" blockGap=16
|
||||
//% blockId=device_pause icon="\uf110"
|
||||
//% pause.shadow=timePicker
|
||||
void pause(int ms) {
|
||||
fiber_sleep(ms);
|
||||
}
|
||||
|
@ -28,7 +28,10 @@ enum Colors {
|
||||
Purple = 0x00FF00FF,
|
||||
//% blockIdentity=basic.color
|
||||
//% block=white
|
||||
White = 0xFF00000
|
||||
White = 0xFFFFFFFF,
|
||||
//% blockIdentity=basic.color
|
||||
//% block=off
|
||||
Off = 0x00000000,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,6 +39,7 @@ enum Colors {
|
||||
*/
|
||||
//% color=#54C9C9 weight=100
|
||||
namespace basic {
|
||||
|
||||
/**
|
||||
* Converts the color name to a number
|
||||
*/
|
||||
@ -56,4 +60,17 @@ namespace basic {
|
||||
export function rgbw(red: number, green: number, blue: number, white:number): number {
|
||||
return ((white & 0xFF) << 24) | ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.
|
||||
* @param interval speed of scroll; eg: 150, 100, 200, -100
|
||||
*/
|
||||
//% help=basic/show-number
|
||||
//% weight=96
|
||||
//% blockId=device_show_number block="show|number %number" blockGap=8
|
||||
//% async
|
||||
//% parts="ledmatrix" interval.defl=150
|
||||
export function showNumber(value: number, interval?: number) {
|
||||
showString(Math.roundWithPrecision(value, 2).toString(), interval);
|
||||
}
|
||||
}
|
||||
|
53
libs/core/blocks-test/basic.blocks
Normal file
@ -0,0 +1,53 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="PGGhch1kuMF##st8~wFr">receivedNumber</variable>
|
||||
</variables>
|
||||
<block type="pxt-on-start" x="77" y="38">
|
||||
<statement name="HANDLER">
|
||||
<block type="device_show_number">
|
||||
<value name="number">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">12</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="basic_show_icon">
|
||||
<field name="i">IconNames.Umbrella</field>
|
||||
<next>
|
||||
<block type="device_print_message">
|
||||
<value name="text">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">hi!</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_pause">
|
||||
<value name="pause">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_clear_display">
|
||||
<next>
|
||||
<block type="basic_show_arrow">
|
||||
<value name="i">
|
||||
<shadow type="device_arrow">
|
||||
<field name="arrow">ArrowNames.South</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_forever" x="418" y="25"></block>
|
||||
</xml>
|
66
libs/core/blocks-test/control.blocks
Normal file
@ -0,0 +1,66 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="tgDN]qF_Ah1Z*?=|+?^Y">item</variable>
|
||||
</variables>
|
||||
<block type="control_in_background" x="-13" y="175">
|
||||
<statement name="HANDLER">
|
||||
<block type="control_reset">
|
||||
<next>
|
||||
<block type="control_wait_us">
|
||||
<value name="micros">
|
||||
<shadow type="math_number" id="w]G5E,EGl+SOB?91N4SV">
|
||||
<field name="NUM">4</field>
|
||||
</shadow>
|
||||
<block type="control_event_timestamp""></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="control_raise_event">
|
||||
<value name="src">
|
||||
<shadow type="control_event_source_id" id="~$#[A%Y{}%ZvxA7_z/6+">
|
||||
<field name="id">EventBusSource.MICROBIT_ID_BUTTON_A</field>
|
||||
</shadow>
|
||||
<block type="control_event_value""></block>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="control_event_value_id" id="=OWyqW(E=RBE^i;;QC0$">
|
||||
<field name="id">EventBusValue.MICROBIT_EVT_ANY</field>
|
||||
</shadow>
|
||||
<block type="control_device_serial_number"></block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="control_on_event" x="-58" y="393">
|
||||
<value name="src">
|
||||
<shadow type="control_event_source_id" id="o,i-zrB1+%JG/,EC.6zB">
|
||||
<field name="id">EventBusSource.MICROBIT_ID_BUTTON_A</field>
|
||||
</shadow>
|
||||
<block type="control_event_value_id">
|
||||
<field name="id">EventBusValue.MES_DPAD_BUTTON_C_UP</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="control_event_value_id" id="n2s(-M;{|izma6OZGq:F">
|
||||
<field name="id">EventBusValue.MICROBIT_EVT_ANY</field>
|
||||
</shadow>
|
||||
<block type="control_event_value_id">
|
||||
<field name="id">EventBusValue.MES_REMOTE_CONTROL_EVT_PLAY</field>
|
||||
</block>
|
||||
</value>
|
||||
<statement name="HANDLER">
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="tgDN]qF_Ah1Z*?=|+?^Y" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="$3|;#yTHhAwO-r1Bsk:B">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="control_device_name"></block>
|
||||
</value>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
183
libs/core/blocks-test/game.blocks
Normal file
@ -0,0 +1,183 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="B{fp`0m8viO6.2a3):}D">item</variable>
|
||||
<variable type="" id=")IrU.C_Qui4E3llvPl7H">gdfgsdfg</variable>
|
||||
</variables>
|
||||
<block type="pxt-on-start" x="246" y="25">
|
||||
<statement name="HANDLER">
|
||||
<block type="game_delete_sprite">
|
||||
<value name="this">
|
||||
<block type="game_create_sprite">
|
||||
<value name="x">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_move_sprite">
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="leds">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_turn_sprite">
|
||||
<field name="direction">Direction.Right</field>
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="degrees">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">45</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_sprite_change_xy">
|
||||
<field name="property">LedSpriteProperty.X</field>
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_sprite_set_property">
|
||||
<field name="property">LedSpriteProperty.X</field>
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="math_number" id="sRSKKdl8vYSc1rPg4mA2">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="game_sprite_property">
|
||||
<field name="property">LedSpriteProperty.X</field>
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")IrU.C_Qui4E3llvPl7H" variabletype="">gdfgsdfg</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="}{^7O7X5I9`!f`OhoEk1">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="game_sprite_touching_sprite">
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="other">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")IrU.C_Qui4E3llvPl7H" variabletype="">gdfgsdfg</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="}{^7O7X5I9`!f`OhoEk1">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="game_sprite_touching_edge">
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_sprite_bounce">
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_add_score">
|
||||
<value name="points">
|
||||
<shadow type="math_number" id="Z8k_T^n:89Tv{RiBQP!$">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
<block type="game_score"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_set_score">
|
||||
<value name="points">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_start_countdown">
|
||||
<value name="duration">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="game_game_over"></block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="variables_set" disabled="true" x="-76" y="44">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="variables_get" disabled="true" x="-92" y="111">
|
||||
<field name="VAR" id="B{fp`0m8viO6.2a3):}D" variabletype="">item</field>
|
||||
</block>
|
||||
</xml>
|
46
libs/core/blocks-test/image.blocks
Normal file
@ -0,0 +1,46 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="tgDN]qF_Ah1Z*?=|+?^Y">item</variable>
|
||||
</variables>
|
||||
<block type="pxt-on-start" x="-29" y="116">
|
||||
<statement name="HANDLER">
|
||||
<block type="device_show_image_offset">
|
||||
<value name="sprite">
|
||||
<block type="builtin_image">
|
||||
<field name="i">IconNames.Heart</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="offset">
|
||||
<shadow type="math_number" id="KX(1%=^vQUd=Q`UHhD*n">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_arrow">
|
||||
<field name="arrow">ArrowNames.South</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_scroll_image">
|
||||
<value name="sprite">
|
||||
<block type="builtin_arrow_image">
|
||||
<field name="i">ArrowNames.SouthWest</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="frameoffset">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="delay">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">200</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="variables_get" disabled="true" x="145" y="168">
|
||||
<field name="VAR" id="tgDN]qF_Ah1Z*?=|+?^Y" variabletype="">item</field>
|
||||
</block>
|
||||
</xml>
|
132
libs/core/blocks-test/input.blocks
Normal file
@ -0,0 +1,132 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="wUkGVHoc@p^mter~Rc7h">item</variable>
|
||||
<variable type="" id=")f$ml.CVl6|1^?sPWl:;">sdfsadf</variable>
|
||||
</variables>
|
||||
<block type="device_button_event" x="-6" y="17">
|
||||
<field name="NAME">Button.AB</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="wUkGVHoc@p^mter~Rc7h" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="*jGI?[NsA.f}=qk0RHHf">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_button2">
|
||||
<field name="NAME">Button.B</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="wUkGVHoc@p^mter~Rc7h" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="*jGI?[NsA.f}=qk0RHHf">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_pin_is_pressed">
|
||||
<field name="NAME">TouchPin.P1</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="bZBPUCLiZ6#D@e_[Y`:0">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_acceleration">
|
||||
<field name="NAME">Dimension.Y</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="bZBPUCLiZ6#D@e_[Y`:0">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_light_level"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="bZBPUCLiZ6#D@e_[Y`:0">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_heading"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="bZBPUCLiZ6#D@e_[Y`:0">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_temperature"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="o~k},FK*r@[O2)Cy!lM}">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_rotation">
|
||||
<field name="NAME">Rotation.Roll</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="Uu,ZpYs7!BzIpX`%V_^!">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_magnetic_force">
|
||||
<field name="NAME">Dimension.Z</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id=")f$ml.CVl6|1^?sPWl:;" variabletype="">sdfsadf</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="s{USu#UBc84Ao*jy(EQC">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_running_time"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_accelerometer_range">
|
||||
<field name="range">AcceleratorRange.TwoG</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_gesture_event" x="472" y="-8">
|
||||
<field name="NAME">Gesture.SixG</field>
|
||||
</block>
|
||||
<block type="device_pin_event" x="555" y="96">
|
||||
<field name="name">TouchPin.P2</field>
|
||||
</block>
|
||||
<block type="device_pin_released" x="188" y="435">
|
||||
<field name="NAME">TouchPin.P2</field>
|
||||
</block>
|
||||
</xml>
|
114
libs/core/blocks-test/led.blocks
Normal file
@ -0,0 +1,114 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<block type="pxt-on-start" x="20" y="20">
|
||||
<statement name="HANDLER">
|
||||
<block type="device_plot">
|
||||
<value name="x">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_unplot">
|
||||
<value name="x">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_led_toggle">
|
||||
<value name="x">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_plot_bar_graph">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="high">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_plot_brightness">
|
||||
<value name="x">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
<block type="device_get_brightness"></block>
|
||||
</value>
|
||||
<value name="brightness">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_brightness">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_stop_animation">
|
||||
<next>
|
||||
<block type="device_led_enable">
|
||||
<value name="on">
|
||||
<shadow type="logic_boolean" id="F!|?!lo8YkE4p2I@MDy?">
|
||||
<field name="BOOL">FALSE</field>
|
||||
</shadow>
|
||||
<block type="device_point">
|
||||
<value name="x">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
95
libs/core/blocks-test/music.blocks
Normal file
@ -0,0 +1,95 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="I3xB5Q]ehg#-~(sq{[|E">item</variable>
|
||||
</variables>
|
||||
<block type="melody_on_event" x="-27" y="128">
|
||||
<field name="value">MusicEvent.BackgroundMelodyStarted</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_play_note">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="name">175</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="duration">
|
||||
<shadow type="device_beat">
|
||||
<field name="fraction">BeatFraction.Sixteenth</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_ring">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="name">147</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_rest">
|
||||
<value name="duration">
|
||||
<shadow type="device_beat">
|
||||
<field name="fraction">BeatFraction.Sixteenth</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="I3xB5Q]ehg#-~(sq{[|E" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="8/Ht9pG0DuL-0~sPe},^">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_note">
|
||||
<field name="name">466</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="I3xB5Q]ehg#-~(sq{[|E" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="8/Ht9pG0DuL-0~sPe},^">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_beat">
|
||||
<field name="fraction">BeatFraction.Sixteenth</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="I3xB5Q]ehg#-~(sq{[|E" variabletype="">item</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="8/Ht9pG0DuL-0~sPe},^">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_tempo"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_change_tempo">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1242</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_tempo">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
209
libs/core/blocks-test/pins.blocks
Normal file
@ -0,0 +1,209 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<block type="pins_on_pulsed" x="-157" y="130">
|
||||
<field name="pin">DigitalPin.P5</field>
|
||||
<field name="pulse">PulseValue.Low</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_set_analog_pin">
|
||||
<field name="name">AnalogPin.P9</field>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_analog_period">
|
||||
<field name="pin">AnalogPin.P10</field>
|
||||
<value name="micros">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">20000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_digital_pin">
|
||||
<field name="name">DigitalPin.P6</field>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_servo_pin">
|
||||
<field name="name">AnalogPin.P13</field>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_servo_pulse">
|
||||
<field name="value">AnalogPin.P8</field>
|
||||
<value name="micros">
|
||||
<shadow type="math_number" id="Hx4bpmg|8KSH=b_`+XtP">
|
||||
<field name="NUM">1500</field>
|
||||
</shadow>
|
||||
<block type="math_map">
|
||||
<value name="value">
|
||||
<shadow type="math_number" id="J%8`=~h4-?O{fY59%(_{">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="pins_i2c_readnumber">
|
||||
<field name="format">NumberFormat.Int8BE</field>
|
||||
<value name="address">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="repeat">
|
||||
<shadow type="logic_boolean">
|
||||
<field name="BOOL">FALSE</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="fromLow">
|
||||
<shadow type="math_number" id="kp(!mScnCVWI/1_X|ar#">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="pins_pulse_in">
|
||||
<field name="name">DigitalPin.P9</field>
|
||||
<field name="value">PulseValue.Low</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="fromHigh">
|
||||
<shadow type="math_number" id="]@F=`[ZuxAk,=05Yyn[{">
|
||||
<field name="NUM">1023</field>
|
||||
</shadow>
|
||||
<block type="pins_pulse_duration"></block>
|
||||
</value>
|
||||
<value name="toLow">
|
||||
<shadow type="math_number" id="sJDL?hoabUE)cDdBJWO=">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="spi_write">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="toHigh">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">4</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="i2c_writenumber">
|
||||
<field name="format">NumberFormat.Int16BE</field>
|
||||
<value name="address">
|
||||
<shadow type="math_number" id="RjJ{^G_#*rwUqER:]i-L">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_digital_pin">
|
||||
<field name="name">DigitalPin.P9</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="math_number" id="CCl{zdVU/!(bR}aUfG,G">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_analog_pin">
|
||||
<field name="name">AnalogPin.P9</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="repeat">
|
||||
<shadow type="logic_boolean">
|
||||
<field name="BOOL">FALSE</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="spi_pins">
|
||||
<field name="mosi">DigitalPin.P11</field>
|
||||
<field name="miso">DigitalPin.P9</field>
|
||||
<field name="sck">DigitalPin.P10</field>
|
||||
<next>
|
||||
<block type="device_set_pull">
|
||||
<field name="pin">DigitalPin.P9</field>
|
||||
<field name="pull">PinPullMode.PullDown</field>
|
||||
<next>
|
||||
<block type="device_analog_pitch">
|
||||
<value name="frequency">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ms">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_pin_events">
|
||||
<field name="pin">DigitalPin.P8</field>
|
||||
<field name="type">PinEventType.Touch</field>
|
||||
<next>
|
||||
<block type="device_analog_set_pitch_pin">
|
||||
<field name="name">AnalogPin.P9</field>
|
||||
<next>
|
||||
<block type="spi_format">
|
||||
<value name="bits">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">8</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="mode">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">3</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="spi_format">
|
||||
<value name="bits">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">8</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="mode">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">3</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="spi_frequency">
|
||||
<value name="frequency">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1000000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
94
libs/core/blocks-test/serial.blocks
Normal file
@ -0,0 +1,94 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="3ch~y{k6dWI;q}kA]3pa">item</variable>
|
||||
</variables>
|
||||
<block type="serial_on_data_received" x="79" y="287">
|
||||
<value name="delimiters">
|
||||
<shadow type="serial_delimiter_conv" id="Rgi{j+glSZt}8nIn!+08">
|
||||
<field name="del">Delimiters.Colon</field>
|
||||
</shadow>
|
||||
<block type="serial_read_buffer"></block>
|
||||
</value>
|
||||
<statement name="HANDLER">
|
||||
<block type="serial_writeline">
|
||||
<value name="text">
|
||||
<shadow type="text" id="re1R]taer}HU[ed30FDZ">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
<block type="serial_read_line"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writenumber">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writevalue">
|
||||
<value name="name">
|
||||
<shadow type="text" id="Y9NXoV7DPB{.(T=w:ei^">
|
||||
<field name="TEXT">x</field>
|
||||
</shadow>
|
||||
<block type="serial_read_until">
|
||||
<value name="delimiter">
|
||||
<shadow type="serial_delimiter_conv">
|
||||
<field name="del">Delimiters.Colon</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writestring">
|
||||
<value name="text">
|
||||
<shadow type="text">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writenumbers">
|
||||
<value name="values">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="3ch~y{k6dWI;q}kA]3pa" variabletype="">item</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_redirect">
|
||||
<field name="tx">SerialPin.P12</field>
|
||||
<field name="rx">SerialPin.P13</field>
|
||||
<field name="rate">BaudRate.BaudRate28800</field>
|
||||
<next>
|
||||
<block type="serial_writebuffer">
|
||||
<value name="buffer">
|
||||
<block type="serial_readbuffer">
|
||||
<value name="length">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">64</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_redirect_to_usb"></block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
677
libs/core/blocks-test/test.blocks
Normal file
@ -0,0 +1,677 @@
|
||||
<xml xmlns="http://www.w3.org/1999/xhtml">
|
||||
<variables>
|
||||
<variable type="" id="2w47B[B-y%SK,+8+DQGz">booltest</variable>
|
||||
<variable type="" id="Uv6@%!N7Ts}XI7t+j[zB">myImage</variable>
|
||||
<variable type="" id="7BPQp@}m*I210zEM4S=3">strtest</variable>
|
||||
</variables>
|
||||
<block type="pxt-on-start" x="481" y="68">
|
||||
<statement name="HANDLER">
|
||||
<block type="device_show_number">
|
||||
<value name="number">
|
||||
<shadow type="math_number" id=")RB0,?b3RM|TO|?[ZPG6">
|
||||
<field name="NUM">123</field>
|
||||
</shadow>
|
||||
<block type="control_event_value""></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_show_leds">
|
||||
<field name="LEDS">`
|
||||
# . . # .
|
||||
# . . # .
|
||||
. # . . .
|
||||
. # # . .
|
||||
. . . . .
|
||||
`
|
||||
</field>
|
||||
<next>
|
||||
<block type="basic_show_icon">
|
||||
<field name="i">IconNames.Heart</field>
|
||||
<next>
|
||||
<block type="device_pause">
|
||||
<value name="pause">
|
||||
<shadow type="timePicker">
|
||||
<field name="ms">500</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_clear_display">
|
||||
<next>
|
||||
<block type="basic_show_arrow">
|
||||
<value name="i">
|
||||
<shadow type="device_arrow">
|
||||
<field name="arrow">ArrowNames.SouthEast</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_show_image_offset">
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="Uv6@%!N7Ts}XI7t+j[zB" variabletype="">myImage</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="offset">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_scroll_image">
|
||||
<value name="sprite">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="Uv6@%!N7Ts}XI7t+j[zB" variabletype="">myImage</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="frameoffset">
|
||||
<shadow type="math_number" id="xu?]Tdz!8RfpHlMjG)~B">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
<block type="control_device_serial_number"></block>
|
||||
</value>
|
||||
<value name="delay">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">200</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="7BPQp@}m*I210zEM4S=3" variabletype="">strtest</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="W]w@ImzxKDQ=.w+$$f4a">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="serial_read_until">
|
||||
<value name="delimiter">
|
||||
<shadow type="serial_delimiter_conv">
|
||||
<field name="del">Delimiters.Hash</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="7BPQp@}m*I210zEM4S=3" variabletype="">strtest</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="W]w@ImzxKDQ=.w+$$f4a">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="serial_read_buffer"></block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_pin_event" x="2407" y="0">
|
||||
<field name="name">TouchPin.P2</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_led_toggle">
|
||||
<value name="x">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="X" precision="1"></mutation>
|
||||
<field name="SLIDER">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="Y" precision="1"></mutation>
|
||||
<field name="SLIDER">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_plot_bar_graph">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="high">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">45</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="led_set_display_mode">
|
||||
<field name="mode">DisplayMode.Greyscale</field>
|
||||
<next>
|
||||
<block type="device_set_analog_pin">
|
||||
<field name="name">AnalogPin.P4</field>
|
||||
<value name="value">
|
||||
<shadow type="math_number_minmax" id=",:%8N*FL3wa-zFQ[+^$9">
|
||||
<mutation min="0" max="1023" label="Value"></mutation>
|
||||
<field name="SLIDER">1023</field>
|
||||
</shadow>
|
||||
<block type="device_get_analog_pin">
|
||||
<field name="name">AnalogPin.P13</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_digital_pin">
|
||||
<field name="name">DigitalPin.P10</field>
|
||||
<value name="value">
|
||||
<shadow type="math_number_minmax" id="W~pvdj%jFEj?EHmT{81Z">
|
||||
<mutation min="0" max="1" label="Value"></mutation>
|
||||
<field name="SLIDER">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_digital_pin">
|
||||
<field name="name">DigitalPin.P15</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_analog_period">
|
||||
<field name="pin">AnalogPin.P9</field>
|
||||
<value name="micros">
|
||||
<shadow type="math_number" id="4a@.1MdG`n=p;34mQOpC">
|
||||
<field name="NUM">1234</field>
|
||||
</shadow>
|
||||
<block type="pin_map">
|
||||
<value name="value">
|
||||
<shadow type="math_number" id="lTWI!)d`ZkwvZW))3X(F">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_temperature"></block>
|
||||
</value>
|
||||
<value name="fromLow">
|
||||
<shadow type="math_number" id="2n.VJ_pD7wFdcjM:FToF">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_heading"></block>
|
||||
</value>
|
||||
<value name="fromHigh">
|
||||
<shadow type="math_number" id="-c^:x{=$`RLP5RW9}{6a">
|
||||
<field name="NUM">1023</field>
|
||||
</shadow>
|
||||
<block type="device_get_rotation">
|
||||
<field name="NAME">Rotation.Roll</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="toLow">
|
||||
<shadow type="math_number" id="#1@Uxq:nFqe!(pHawH9H">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_magnetic_force">
|
||||
<field name="NAME">Dimension.Y</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="toHigh">
|
||||
<shadow type="math_number" id="?%tD/NB|a$cg#TU0/C02">
|
||||
<field name="NUM">4</field>
|
||||
</shadow>
|
||||
<block type="device_get_running_time"></block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_servo_pin">
|
||||
<field name="name">AnalogPin.P20</field>
|
||||
<value name="value">
|
||||
<shadow type="math_number_minmax" id="xC9lYf`{!gA-A8R+#~L.">
|
||||
<mutation min="0" max="180" label="Value"></mutation>
|
||||
<field name="SLIDER">180</field>
|
||||
</shadow>
|
||||
<block type="device_acceleration">
|
||||
<field name="NAME">Dimension.Z</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_servo_pulse">
|
||||
<field name="value">AnalogPin.P14</field>
|
||||
<value name="micros">
|
||||
<shadow type="math_number" id="@*C3kzJkeeUQ@s$N5?K}">
|
||||
<field name="NUM">1500</field>
|
||||
</shadow>
|
||||
<block type="device_get_light_level"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_play_note">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="name">220</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="duration">
|
||||
<shadow type="device_beat">
|
||||
<field name="fraction">BeatFraction.Sixteenth</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_ring">
|
||||
<value name="note">
|
||||
<shadow type="device_note">
|
||||
<field name="name">659</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_rest">
|
||||
<value name="duration">
|
||||
<shadow type="device_beat">
|
||||
<field name="fraction">BeatFraction.Double</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_start_melody">
|
||||
<field name="options">MelodyOptions.ForeverInBackground</field>
|
||||
<value name="melody">
|
||||
<shadow type="device_builtin_melody">
|
||||
<field name="melody">Melodies.Ringtone</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_gesture_event" x="1570" y="56">
|
||||
<field name="NAME">Gesture.TiltLeft</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_unplot">
|
||||
<value name="x">
|
||||
<shadow type="math_number_minmax" id="|}V%t{K/j77J}J54FX]r">
|
||||
<mutation min="0" max="4" label="X" precision="1"></mutation>
|
||||
<field name="SLIDER">1</field>
|
||||
</shadow>
|
||||
<block type="control_event_value_id">
|
||||
<field name="id">EventBusValue.MICROBIT_PIN_EVT_PULSE_HI</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="Y" precision="1"></mutation>
|
||||
<field name="SLIDER">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writebuffer">
|
||||
<value name="buffer">
|
||||
<shadow type="serial_readbuffer">
|
||||
<value name="length">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">64</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_forever" x="1172" y="242">
|
||||
<statement name="HANDLER">
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="2w47B[B-y%SK,+8+DQGz" variabletype="">booltest</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="RP?w4vFS1wB4I0nNyldb">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_get_button2">
|
||||
<field name="NAME">Button.B</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="2w47B[B-y%SK,+8+DQGz" variabletype="">booltest</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="RP?w4vFS1wB4I0nNyldb">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_pin_is_pressed">
|
||||
<field name="NAME">TouchPin.P2</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set">
|
||||
<field name="VAR" id="2w47B[B-y%SK,+8+DQGz" variabletype="">booltest</field>
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number" id="RP?w4vFS1wB4I0nNyldb">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="device_point">
|
||||
<value name="x">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="X" precision="1"></mutation>
|
||||
<field name="SLIDER">3</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="Y" precision="1"></mutation>
|
||||
<field name="SLIDER">4</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_button_event" x="1294" y="513">
|
||||
<field name="NAME">Button.AB</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_plot">
|
||||
<value name="x">
|
||||
<shadow type="math_number_minmax" id="Z[BsF}r)3:FoNWE|X5}s">
|
||||
<mutation min="0" max="4" label="X" precision="1"></mutation>
|
||||
<field name="SLIDER">1</field>
|
||||
</shadow>
|
||||
<block type="device_beat">
|
||||
<field name="fraction">BeatFraction.Sixteenth</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="Y" precision="1"></mutation>
|
||||
<field name="SLIDER">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_plot_brightness">
|
||||
<value name="x">
|
||||
<shadow type="math_number_minmax" id="2we6or2Y|vhAl!^BAYtl">
|
||||
<mutation min="0" max="4" label="X" precision="1"></mutation>
|
||||
<field name="SLIDER">3</field>
|
||||
</shadow>
|
||||
<block type="device_tempo"></block>
|
||||
</value>
|
||||
<value name="y">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="0" max="4" label="Y" precision="1"></mutation>
|
||||
<field name="SLIDER">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="brightness">
|
||||
<shadow type="math_number_minmax" id="IjJTgf5z!,K`qd`~pCB3">
|
||||
<mutation min="0" max="255" label="Brightness"></mutation>
|
||||
<field name="SLIDER">255</field>
|
||||
</shadow>
|
||||
<block type="device_get_brightness"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_brightness">
|
||||
<value name="value">
|
||||
<shadow type="math_number_minmax" id="WAUzdT@1z{%:UNn!_dU(">
|
||||
<mutation min="0" max="255" label="Value"></mutation>
|
||||
<field name="SLIDER">255</field>
|
||||
</shadow>
|
||||
<block type="device_note">
|
||||
<field name="name">440</field>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_stop_animation">
|
||||
<next>
|
||||
<block type="device_led_enable">
|
||||
<value name="on">
|
||||
<shadow type="logic_boolean">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="input_compass_calibrate"></block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="control_in_background" x="0" y="635">
|
||||
<statement name="HANDLER">
|
||||
<block type="control_wait_us">
|
||||
<value name="micros">
|
||||
<shadow type="math_number" id="^!;AKS(vo=ly}ykm1~Z|">
|
||||
<field name="NUM">4</field>
|
||||
</shadow>
|
||||
<block type="control_event_timestamp""></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="control_raise_event">
|
||||
<value name="src">
|
||||
<shadow type="control_event_source_id">
|
||||
<field name="id">EventBusSource.MICROBIT_ID_IO_P0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="control_event_value_id">
|
||||
<field name="id">EventBusValue.MES_ALERT_EVT_ALARM1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="device_pin_released" x="942" y="723">
|
||||
<field name="NAME">TouchPin.P2</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_set_accelerometer_range">
|
||||
<field name="range">AcceleratorRange.EightG</field>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="serial_on_data_received" x="419" y="933">
|
||||
<value name="delimiters">
|
||||
<shadow type="serial_delimiter_conv">
|
||||
<field name="del">Delimiters.Colon</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<statement name="HANDLER">
|
||||
<block type="serial_redirect">
|
||||
<field name="tx">SerialPin.P12</field>
|
||||
<field name="rx">SerialPin.P14</field>
|
||||
<field name="rate">BaudRate.BaudRate19200</field>
|
||||
<next>
|
||||
<block type="serial_redirect_to_usb"></block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="pins_on_pulsed" x="1538" y="929">
|
||||
<field name="pin">DigitalPin.P10</field>
|
||||
<field name="pulse">PulseValue.Low</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="i2c_writenumber">
|
||||
<field name="format">NumberFormat.UInt8BE</field>
|
||||
<value name="address">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="repeat">
|
||||
<shadow type="logic_boolean">
|
||||
<field name="BOOL">FALSE</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_analog_pitch">
|
||||
<value name="frequency">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ms">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_pin_events">
|
||||
<field name="pin">DigitalPin.P0</field>
|
||||
<field name="type">PinEventType.Touch</field>
|
||||
<next>
|
||||
<block type="spi_frequency">
|
||||
<value name="frequency">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1000000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_analog_set_pitch_pin">
|
||||
<field name="name">AnalogPin.P2</field>
|
||||
<next>
|
||||
<block type="device_set_pull">
|
||||
<field name="pin">DigitalPin.P2</field>
|
||||
<field name="pull">PinPullMode.PullDown</field>
|
||||
<next>
|
||||
<block type="spi_format">
|
||||
<value name="bits">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">8</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="mode">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">3</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="spi_pins">
|
||||
<field name="mosi">DigitalPin.P9</field>
|
||||
<field name="miso">DigitalPin.P14</field>
|
||||
<field name="sck">DigitalPin.P16</field>
|
||||
<next>
|
||||
<block type="control_reset"></block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="melody_on_event" x="859" y="1002">
|
||||
<field name="value">MusicEvent.BackgroundMelodyNotePlayed</field>
|
||||
<statement name="HANDLER">
|
||||
<block type="device_change_tempo">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">123</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="device_set_tempo">
|
||||
<value name="value">
|
||||
<shadow type="math_number_minmax">
|
||||
<mutation min="4" max="400" label="Bpm" precision="0"></mutation>
|
||||
<field name="SLIDER">12312312</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writeline">
|
||||
<value name="text">
|
||||
<shadow type="text" id="SYl:x9lxu0KI{YcmomQz">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
<block type="serial_read_line"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writenumber">
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writevalue">
|
||||
<value name="name">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">x</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="serial_writestring">
|
||||
<value name="text">
|
||||
<shadow type="text" id="_gp`6rz8ZI+em9ILvR~6">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
<block type="control_device_name"></block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="control_on_event" x="24" y="1406">
|
||||
<value name="src">
|
||||
<shadow type="control_event_source_id">
|
||||
<field name="id">EventBusSource.MICROBIT_ID_IO_P1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="value">
|
||||
<shadow type="control_event_value_id">
|
||||
<field name="id">EventBusValue.MES_ALERT_EVT_ALARM2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</xml>
|
@ -1,160 +0,0 @@
|
||||
#include "pxt.h"
|
||||
|
||||
// keep in sync with github/pxt/pxtsim/libgeneric.ts
|
||||
enum class NumberFormat {
|
||||
Int8LE = 1,
|
||||
UInt8LE,
|
||||
Int16LE,
|
||||
UInt16LE,
|
||||
Int32LE,
|
||||
Int8BE,
|
||||
UInt8BE,
|
||||
Int16BE,
|
||||
UInt16BE,
|
||||
Int32BE,
|
||||
// UInt32,
|
||||
};
|
||||
|
||||
//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte
|
||||
namespace BufferMethods {
|
||||
//%
|
||||
int getByte(Buffer buf, int off) {
|
||||
return max(ManagedBuffer(buf).getByte(off), 0);
|
||||
}
|
||||
|
||||
//%
|
||||
void setByte(Buffer buf, int off, int v) {
|
||||
ManagedBuffer(buf).setByte(off, v);
|
||||
}
|
||||
|
||||
//%
|
||||
uint8_t *getBytes(Buffer buf) {
|
||||
return buf->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a number in specified format in the buffer.
|
||||
*/
|
||||
//%
|
||||
void setNumber(Buffer buf, NumberFormat format, int offset, int value)
|
||||
{
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
int32_t i32;
|
||||
|
||||
ManagedBuffer b(buf);
|
||||
|
||||
// Assume little endian
|
||||
#define WRITEBYTES(isz, swap) isz = value; b.writeBytes(offset, (uint8_t*)&isz, sizeof(isz), swap); break
|
||||
|
||||
switch (format) {
|
||||
case NumberFormat::Int8LE: WRITEBYTES(i8, false);
|
||||
case NumberFormat::UInt8LE: WRITEBYTES(u8, false);
|
||||
case NumberFormat::Int16LE: WRITEBYTES(i16, false);
|
||||
case NumberFormat::UInt16LE: WRITEBYTES(u16, false);
|
||||
case NumberFormat::Int32LE: WRITEBYTES(i32, false);
|
||||
case NumberFormat::Int8BE: WRITEBYTES(i8, true);
|
||||
case NumberFormat::UInt8BE: WRITEBYTES(u8, true);
|
||||
case NumberFormat::Int16BE: WRITEBYTES(i16, true);
|
||||
case NumberFormat::UInt16BE: WRITEBYTES(u16, true);
|
||||
case NumberFormat::Int32BE: WRITEBYTES(i32, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a number in specified format from the buffer.
|
||||
*/
|
||||
//%
|
||||
int getNumber(Buffer buf, NumberFormat format, int offset)
|
||||
{
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
int32_t i32;
|
||||
|
||||
ManagedBuffer b(buf);
|
||||
|
||||
// Assume little endian
|
||||
#define READBYTES(isz, swap) b.readBytes((uint8_t*)&isz, offset, sizeof(isz), swap); return isz
|
||||
|
||||
switch (format) {
|
||||
case NumberFormat::Int8LE: READBYTES(i8, false);
|
||||
case NumberFormat::UInt8LE: READBYTES(u8, false);
|
||||
case NumberFormat::Int16LE: READBYTES(i16, false);
|
||||
case NumberFormat::UInt16LE: READBYTES(u16, false);
|
||||
case NumberFormat::Int32LE: READBYTES(i32, false);
|
||||
case NumberFormat::Int8BE: READBYTES(i8, true);
|
||||
case NumberFormat::UInt8BE: READBYTES(u8, true);
|
||||
case NumberFormat::Int16BE: READBYTES(i16, true);
|
||||
case NumberFormat::UInt16BE: READBYTES(u16, true);
|
||||
case NumberFormat::Int32BE: READBYTES(i32, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the length of a Buffer object. */
|
||||
//% property
|
||||
int length(Buffer s) {
|
||||
return s->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill (a fragment) of the buffer with given value.
|
||||
*/
|
||||
//%
|
||||
void fill(Buffer buf, int value, int offset = 0, int length = -1)
|
||||
{
|
||||
ManagedBuffer(buf).fill(value, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of a fragment of a buffer.
|
||||
*/
|
||||
//%
|
||||
Buffer slice(Buffer buf, int offset = 0, int length = -1)
|
||||
{
|
||||
return ManagedBuffer(buf).slice(offset, length).leakData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift buffer left in place, with zero padding.
|
||||
* @param offset number of bytes to shift; use negative value to shift right
|
||||
* @param start start offset in buffer. Default is 0.
|
||||
* @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1
|
||||
*/
|
||||
//%
|
||||
void shift(Buffer buf, int offset, int start = 0, int length = -1)
|
||||
{
|
||||
ManagedBuffer(buf).shift(offset, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate buffer left in place.
|
||||
* @param offset number of bytes to shift; use negative value to shift right
|
||||
* @param start start offset in buffer. Default is 0.
|
||||
* @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1
|
||||
*/
|
||||
//%
|
||||
void rotate(Buffer buf, int offset, int start = 0, int length = -1)
|
||||
{
|
||||
ManagedBuffer(buf).rotate(offset, start, length);
|
||||
}
|
||||
|
||||
// int readBytes(uint8_t *dst, int offset, int length, bool swapBytes = false) const;
|
||||
// int writeBytes(int dstOffset, uint8_t *src, int length, bool swapBytes = false);
|
||||
|
||||
/**
|
||||
* Write contents of `src` at `dstOffset` in current buffer.
|
||||
*/
|
||||
//%
|
||||
void write(Buffer buf, int dstOffset, Buffer src)
|
||||
{
|
||||
//Not supported, we only do up to 4 args :/
|
||||
//void write(Buffer buf, int dstOffset, Buffer src, int srcOffset = 0, int length = -1)
|
||||
ManagedBuffer(buf).writeBuffer(dstOffset, ManagedBuffer(src), 0, -1);
|
||||
}
|
||||
}
|
280
libs/core/codal.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
#include "pxt.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
PXT_ABI(__aeabi_dadd)
|
||||
PXT_ABI(__aeabi_dcmplt)
|
||||
PXT_ABI(__aeabi_dcmpgt)
|
||||
PXT_ABI(__aeabi_dsub)
|
||||
PXT_ABI(__aeabi_ddiv)
|
||||
PXT_ABI(__aeabi_dmul)
|
||||
|
||||
extern "C" void target_panic(int error_code) {
|
||||
// wait for serial to flush
|
||||
wait_us(300000);
|
||||
microbit_panic(error_code);
|
||||
}
|
||||
|
||||
extern "C" void target_reset() {
|
||||
microbit_reset();
|
||||
}
|
||||
|
||||
uint32_t device_heap_size(uint8_t heap_index); // defined in microbit-dal
|
||||
|
||||
namespace pxt {
|
||||
|
||||
MicroBit uBit;
|
||||
MicroBitEvent lastEvent;
|
||||
|
||||
void platform_init() {
|
||||
microbit_seed_random();
|
||||
seedRandom(microbit_random(0x7fffffff));
|
||||
}
|
||||
|
||||
void initMicrobitGC() {
|
||||
if (device_heap_size(1) > NON_GC_HEAP_RESERVATION + 4)
|
||||
gcPreAllocateBlock(device_heap_size(1) - NON_GC_HEAP_RESERVATION);
|
||||
}
|
||||
|
||||
void platform_init();
|
||||
void usb_init();
|
||||
|
||||
struct FreeList {
|
||||
FreeList *next;
|
||||
};
|
||||
|
||||
static void initCodal() {
|
||||
|
||||
uBit.init();
|
||||
|
||||
// repeat error 4 times and restart as needed
|
||||
microbit_panic_timeout(4);
|
||||
}
|
||||
|
||||
void dumpDmesg() {}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// An adapter for the API expected by the run-time.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// We have the invariant that if [dispatchEvent] is registered against the DAL
|
||||
// for a given event, then [handlersMap] contains a valid entry for that
|
||||
// event.
|
||||
void dispatchEvent(MicroBitEvent e) {
|
||||
lastEvent = e;
|
||||
|
||||
auto curr = findBinding(e.source, e.value);
|
||||
auto value = fromInt(e.value);
|
||||
if (curr)
|
||||
runAction1(curr->action, value);
|
||||
|
||||
curr = findBinding(e.source, DEVICE_EVT_ANY);
|
||||
if (curr)
|
||||
runAction1(curr->action, value);
|
||||
}
|
||||
|
||||
void registerWithDal(int id, int event, Action a, int flags) {
|
||||
// first time?
|
||||
if (!findBinding(id, event))
|
||||
uBit.messageBus.listen(id, event, dispatchEvent, flags);
|
||||
setBinding(id, event, a);
|
||||
}
|
||||
|
||||
void fiberDone(void *a) {
|
||||
decr((Action)a);
|
||||
unregisterGCPtr((Action)a);
|
||||
release_fiber();
|
||||
}
|
||||
|
||||
void releaseFiber() {
|
||||
release_fiber();
|
||||
}
|
||||
|
||||
void sleep_ms(unsigned ms) {
|
||||
fiber_sleep(ms);
|
||||
}
|
||||
|
||||
void sleep_us(uint64_t us) {
|
||||
wait_us(us);
|
||||
}
|
||||
|
||||
void forever_stub(void *a) {
|
||||
while (true) {
|
||||
runAction0((Action)a);
|
||||
fiber_sleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
void runForever(Action a) {
|
||||
if (a != 0) {
|
||||
incr(a);
|
||||
registerGCPtr(a);
|
||||
create_fiber(forever_stub, (void *)a);
|
||||
}
|
||||
}
|
||||
|
||||
void runInParallel(Action a) {
|
||||
if (a != 0) {
|
||||
incr(a);
|
||||
registerGCPtr(a);
|
||||
create_fiber((void (*)(void *))runAction0, (void *)a, fiberDone);
|
||||
}
|
||||
}
|
||||
|
||||
void waitForEvent(int id, int event) {
|
||||
fiber_wait_for_event(id, event);
|
||||
}
|
||||
|
||||
void initRuntime() {
|
||||
initCodal();
|
||||
platform_init();
|
||||
}
|
||||
|
||||
//%
|
||||
unsigned afterProgramPage() {
|
||||
unsigned ptr = (unsigned)&bytecode[0];
|
||||
ptr += programSize();
|
||||
ptr = (ptr + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int current_time_ms() {
|
||||
return system_timer_current_time();
|
||||
}
|
||||
|
||||
static void logwriten(const char *msg, int l) {
|
||||
uBit.serial.send((uint8_t *)msg, l);
|
||||
}
|
||||
|
||||
static void logwrite(const char *msg) {
|
||||
logwriten(msg, strlen(msg));
|
||||
}
|
||||
|
||||
static void writeNum(char *buf, uint32_t n, bool full) {
|
||||
int i = 0;
|
||||
int sh = 28;
|
||||
while (sh >= 0) {
|
||||
int d = (n >> sh) & 0xf;
|
||||
if (full || d || sh == 0 || i) {
|
||||
buf[i++] = d > 9 ? 'A' + d - 10 : '0' + d;
|
||||
}
|
||||
sh -= 4;
|
||||
}
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
static void logwritenum(uint32_t n, bool full, bool hex) {
|
||||
char buff[20];
|
||||
|
||||
if (hex) {
|
||||
writeNum(buff, n, full);
|
||||
logwrite("0x");
|
||||
} else {
|
||||
itoa(n, buff);
|
||||
}
|
||||
|
||||
logwrite(buff);
|
||||
}
|
||||
|
||||
void vdebuglog(const char *format, va_list ap) {
|
||||
const char *end = format;
|
||||
|
||||
while (*end) {
|
||||
if (*end++ == '%') {
|
||||
logwriten(format, end - format - 1);
|
||||
uint32_t val = va_arg(ap, uint32_t);
|
||||
switch (*end++) {
|
||||
case 'c':
|
||||
logwriten((const char *)&val, 1);
|
||||
break;
|
||||
case 'd':
|
||||
logwritenum(val, false, false);
|
||||
break;
|
||||
case 'x':
|
||||
logwritenum(val, false, true);
|
||||
break;
|
||||
case 'p':
|
||||
case 'X':
|
||||
logwritenum(val, true, true);
|
||||
break;
|
||||
case 's':
|
||||
logwrite((char *)(void *)val);
|
||||
break;
|
||||
case '%':
|
||||
logwrite("%");
|
||||
break;
|
||||
default:
|
||||
logwrite("???");
|
||||
break;
|
||||
}
|
||||
format = end;
|
||||
}
|
||||
}
|
||||
logwriten(format, end - format);
|
||||
logwrite("\n");
|
||||
}
|
||||
|
||||
void debuglog(const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
vdebuglog(format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
void sendSerial(const char *data, int len) {
|
||||
logwriten(data, len);
|
||||
}
|
||||
|
||||
#ifdef PXT_GC
|
||||
ThreadContext *getThreadContext() {
|
||||
if (!currentFiber)
|
||||
return NULL;
|
||||
return (ThreadContext *)currentFiber->user_data;
|
||||
}
|
||||
|
||||
void setThreadContext(ThreadContext *ctx) {
|
||||
currentFiber->user_data = ctx;
|
||||
}
|
||||
|
||||
static void *threadAddressFor(Fiber *fib, void *sp) {
|
||||
if (fib == currentFiber)
|
||||
return sp;
|
||||
return (uint8_t *)sp + ((uint8_t *)fib->stack_top - (uint8_t *)fib->tcb.stack_base);
|
||||
}
|
||||
|
||||
void gcProcessStacks(int flags) {
|
||||
// check scheduler is initialized
|
||||
if (!currentFiber) {
|
||||
// make sure we allocate something to at least initalize the memory allocator
|
||||
void * volatile p = xmalloc(1);
|
||||
xfree(p);
|
||||
return;
|
||||
}
|
||||
|
||||
int numFibers = list_fibers(NULL);
|
||||
Fiber **fibers = (Fiber **)xmalloc(sizeof(Fiber *) * numFibers);
|
||||
int num2 = list_fibers(fibers);
|
||||
if (numFibers != num2)
|
||||
oops(12);
|
||||
int cnt = 0;
|
||||
|
||||
for (int i = 0; i < numFibers; ++i) {
|
||||
auto fib = fibers[i];
|
||||
auto ctx = (ThreadContext *)fib->user_data;
|
||||
if (!ctx)
|
||||
continue;
|
||||
for (auto seg = &ctx->stack; seg; seg = seg->next) {
|
||||
auto ptr = (TValue *)threadAddressFor(fib, seg->top);
|
||||
auto end = (TValue *)threadAddressFor(fib, seg->bottom);
|
||||
if (flags & 2)
|
||||
DMESG("RS%d:%p/%d", cnt++, ptr, end - ptr);
|
||||
// VLOG("mark: %p - %p", ptr, end);
|
||||
while (ptr < end) {
|
||||
gcProcess(*ptr++);
|
||||
}
|
||||
}
|
||||
}
|
||||
xfree(fibers);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace pxt
|
53
libs/core/console.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
/**
|
||||
* Reading and writing data to the console output.
|
||||
*/
|
||||
//% weight=12 color=#002050 icon="\uf120"
|
||||
//% advanced=true
|
||||
namespace console {
|
||||
type Listener = (text: string) => void;
|
||||
|
||||
//% whenUsed
|
||||
let listeners: Listener[] = undefined;
|
||||
|
||||
/**
|
||||
* Write a line of text to the console output.
|
||||
* @param value to send
|
||||
*/
|
||||
//% weight=90
|
||||
//% help=console/log blockGap=8
|
||||
//% text.shadowOptions.toString=true
|
||||
export function log(text: string): void {
|
||||
// pad text on the 32byte boundar
|
||||
text += "\r\n";
|
||||
control.__log(text);
|
||||
// send to listeners
|
||||
if (listeners)
|
||||
for (let i = 0; i < listeners.length; ++i)
|
||||
listeners[i](text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a name:value pair as a line of text to the console output.
|
||||
* @param name name of the value stream, eg: "x"
|
||||
* @param value to write
|
||||
*/
|
||||
//% weight=88 blockGap=8
|
||||
//% help=console/log-value
|
||||
export function logValue(name: string, value: number): void {
|
||||
log(name ? `${name}: ${value}` : `${value}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for the log messages
|
||||
* @param listener
|
||||
*/
|
||||
//%
|
||||
export function addListener(listener: (text: string) => void) {
|
||||
if (!listener) return;
|
||||
if (!listeners)
|
||||
listeners = [];
|
||||
listeners.push(listener);
|
||||
}
|
||||
}
|
@ -71,8 +71,6 @@ enum EventBusSource {
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MICROBIT_ID_IO_P20_ = MICROBIT_ID_IO_P20,
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MICROBIT_ID_IO_P21_ = MICROBIT_ID_IO_P21,
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MES_DEVICE_INFO_ID_ = MES_DEVICE_INFO_ID,
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MES_SIGNAL_STRENGTH_ID_ = MES_SIGNAL_STRENGTH_ID,
|
||||
@ -207,6 +205,15 @@ enum EventBusValue {
|
||||
MES_REMOTE_CONTROL_EVT_VOLUMEUP_ = MES_REMOTE_CONTROL_EVT_VOLUMEUP,
|
||||
};
|
||||
|
||||
enum EventFlags {
|
||||
//%
|
||||
QueueIfBusy = MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY,
|
||||
//%
|
||||
DropIfBusy = MESSAGE_BUS_LISTENER_DROP_IF_BUSY,
|
||||
//%
|
||||
Reentrant = MESSAGE_BUS_LISTENER_REENTRANT
|
||||
};
|
||||
|
||||
//% weight=1 color="#333333"
|
||||
//% advanced=true
|
||||
namespace control {
|
||||
@ -222,7 +229,7 @@ namespace control {
|
||||
//% help=control/in-background blockAllowMultiple=1 afterOnStart=true
|
||||
//% blockId="control_in_background" block="run in background" blockGap=8
|
||||
void inBackground(Action a) {
|
||||
runInBackground(a);
|
||||
runInParallel(a);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,13 +265,14 @@ namespace control {
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an event in the event bus.
|
||||
* Registers an event handler.
|
||||
*/
|
||||
//% weight=20 blockGap=8 blockId="control_on_event" block="on event|from %src=control_event_source_id|with value %value=control_event_value_id"
|
||||
//% help=control/on-event
|
||||
//% blockExternalInputs=1
|
||||
void onEvent(int src, int value, Action handler) {
|
||||
registerWithDal(src, value, handler);
|
||||
void onEvent(int src, int value, Action handler, int flags = 0) {
|
||||
if (!flags) flags = EventFlags::QueueIfBusy;
|
||||
registerWithDal(src, value, handler, (int)flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,12 +296,12 @@ namespace control {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a friendly name for the device derived from the its serial number
|
||||
* Make a friendly name for the device based on its serial number
|
||||
*/
|
||||
//% blockId="control_device_name" block="device name" weight=10 blockGap=8
|
||||
//% advanced=true
|
||||
StringData* deviceName() {
|
||||
return ManagedString(microbit_friendly_name()).leakData();
|
||||
String deviceName() {
|
||||
return mkString(microbit_friendly_name(), -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -304,4 +312,22 @@ namespace control {
|
||||
int deviceSerialNumber() {
|
||||
return microbit_serial_number();
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs simulator/runtime of a MIDI message
|
||||
* Internal function to support the simulator.
|
||||
*/
|
||||
//% part=midioutput blockHidden=1
|
||||
void __midiSend(Buffer buffer) {
|
||||
// this is a stub to support the simulator
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
//%
|
||||
void __log(String text) {
|
||||
if (NULL == text) return;
|
||||
pxt::sendSerial(text->getUTF8Data(), text->getUTF8Size());
|
||||
}
|
||||
}
|
||||
|
@ -4,47 +4,63 @@
|
||||
//% weight=1 color="#42495F" icon="\uf233"
|
||||
//% advanced=true
|
||||
namespace control {
|
||||
|
||||
/**
|
||||
* Returns the value of a C++ runtime constant
|
||||
*/
|
||||
//% weight=2 weight=19 blockId="control_event_source_id" block="%id" blockGap=8
|
||||
//% shim=TD_ID advanced=true
|
||||
export function eventSourceId(id: EventBusSource): number {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* Returns the value of a C++ runtime constant
|
||||
*/
|
||||
//% weight=1 weight=19 blockId="control_event_value_id" block="%id"
|
||||
//% shim=TD_ID advanced=true
|
||||
export function eventValueId(id: EventBusValue): number {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display specified error code and stop the program.
|
||||
*/
|
||||
//% shim=pxtrt::panic
|
||||
export function panic(code: number) { }
|
||||
|
||||
/**
|
||||
* If the condition is false, display msg on serial console, and panic with code 098.
|
||||
*/
|
||||
export function assert(condition: boolean, msg?: string) {
|
||||
if (!condition) {
|
||||
console.log("ASSERTION FAILED")
|
||||
if (msg != null) {
|
||||
console.log(msg)
|
||||
}
|
||||
panic(98)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display warning in the simulator.
|
||||
*/
|
||||
//% shim=pxtrt::runtimeWarning
|
||||
export function runtimeWarning(message: string) { }
|
||||
|
||||
/**
|
||||
* Returns the value of a C++ runtime constant
|
||||
*/
|
||||
//% weight=2 weight=19 blockId="control_event_source_id" block="%id" blockGap=8
|
||||
//% shim=TD_ID advanced=true
|
||||
export function eventSourceId(id: EventBusSource): number {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a C++ runtime constant
|
||||
*/
|
||||
//% weight=1 weight=19 blockId="control_event_value_id" block="%id"
|
||||
//% shim=TD_ID advanced=true
|
||||
export function eventValueId(id: EventBusValue): number {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display specified error code and stop the program.
|
||||
*/
|
||||
//% shim=pxtrt::panic
|
||||
export function panic(code: number) { }
|
||||
|
||||
/**
|
||||
* If the condition is false, display msg on serial console, and panic with code 098.
|
||||
*/
|
||||
export function assert(condition: boolean, msg?: string) {
|
||||
if (!condition) {
|
||||
console.log("ASSERTION FAILED")
|
||||
if (msg != null) {
|
||||
console.log(msg)
|
||||
}
|
||||
panic(98)
|
||||
}
|
||||
}
|
||||
|
||||
export function fail(message: string) {
|
||||
console.log("Fatal failure: ")
|
||||
console.log(message)
|
||||
panic(108)
|
||||
}
|
||||
|
||||
/**
|
||||
* Display warning in the simulator.
|
||||
*/
|
||||
//% shim=pxtrt::runtimeWarning
|
||||
export function runtimeWarning(message: string) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any value to text
|
||||
* @param value value to be converted to text
|
||||
*/
|
||||
//% help=text/convert-to-text weight=1
|
||||
//% block="convert $value=math_number to text"
|
||||
//% blockId=variable_to_text blockNamespace="text"
|
||||
function convertToText(value: any): string {
|
||||
return "" + value;
|
||||
}
|
||||
|
@ -1,436 +0,0 @@
|
||||
#include "pxt.h"
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
namespace String_ {
|
||||
//%
|
||||
StringData *charAt(StringData *s, int pos) {
|
||||
return ManagedString((char)ManagedString(s).charAt(pos)).leakData();
|
||||
}
|
||||
|
||||
//%
|
||||
int charCodeAt(StringData *s, int index) {
|
||||
return ManagedString(s).charAt(index);
|
||||
}
|
||||
|
||||
//%
|
||||
StringData *concat(StringData *s, StringData *other) {
|
||||
ManagedString a(s), b(other);
|
||||
return (a + b).leakData();
|
||||
}
|
||||
|
||||
//%
|
||||
int compare(StringData *s, StringData *that) {
|
||||
int compareResult = strcmp(s->data, that->data);
|
||||
if (compareResult < 0)
|
||||
return -1;
|
||||
else if (compareResult > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//%
|
||||
int compareDecr(StringData *s, StringData *that) {
|
||||
int r = compare(s, that);
|
||||
if (r == 0)
|
||||
decr((uint32_t)that);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//%
|
||||
int length(StringData *s) { return s->len; }
|
||||
|
||||
//%
|
||||
StringData *fromCharCode(int code)
|
||||
{
|
||||
return ManagedString((char)code).leakData();
|
||||
}
|
||||
|
||||
//%
|
||||
int toNumber(StringData *s) {
|
||||
return atoi(s->data);
|
||||
}
|
||||
|
||||
//%
|
||||
StringData *mkEmpty()
|
||||
{
|
||||
return ManagedString::EmptyString.leakData();
|
||||
}
|
||||
|
||||
//%
|
||||
StringData *substr(StringData *s, int start, int length)
|
||||
{
|
||||
if (length <= 0)
|
||||
return mkEmpty();
|
||||
if (start < 0)
|
||||
start = max(s->len + start, 0);
|
||||
length = min(length, s->len - start);
|
||||
ManagedString x(s);
|
||||
return x.substring(start, length).leakData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace Boolean_ {
|
||||
// Cache the string literals "true" and "false" when used.
|
||||
// Note that the representation of booleans stays the usual C-one.
|
||||
|
||||
static const char sTrue[] __attribute__ ((aligned (4))) = "\xff\xff\x04\x00" "true\0";
|
||||
static const char sFalse[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "false\0";
|
||||
|
||||
//%
|
||||
StringData* toString(bool v)
|
||||
{
|
||||
if (v) {
|
||||
return (StringData*)(void*)sTrue;
|
||||
} else {
|
||||
return (StringData*)(void*)sFalse;
|
||||
}
|
||||
}
|
||||
|
||||
//%
|
||||
bool bang(int v) { return v == 0; }
|
||||
}
|
||||
|
||||
namespace Number_ {
|
||||
//%
|
||||
StringData* toString(int n)
|
||||
{
|
||||
return ManagedString(n).leakData();
|
||||
}
|
||||
|
||||
// +, - and friends are handled directly by assembly instructions
|
||||
// The comparisons are here as they are more code-size efficient
|
||||
|
||||
//%
|
||||
bool lt(int x, int y) { return x < y; }
|
||||
//%
|
||||
bool le(int x, int y) { return x <= y; }
|
||||
//%
|
||||
bool neq(int x, int y) { return x != y; }
|
||||
//%
|
||||
bool eq(int x, int y) { return x == y; }
|
||||
//%
|
||||
bool gt(int x, int y) { return x > y; }
|
||||
//%
|
||||
bool ge(int x, int y) { return x >= y; }
|
||||
|
||||
// These in fact call into C runtime on Cortex-M0
|
||||
//%
|
||||
int div(int x, int y) { return x / y; }
|
||||
//%
|
||||
int mod(int x, int y) { return x % y; }
|
||||
|
||||
//%
|
||||
bool eqDecr(int x, int y) {
|
||||
if(x == y) {
|
||||
decr(y);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Math_ {
|
||||
//%
|
||||
int pow(int x, int y)
|
||||
{
|
||||
if (y < 0)
|
||||
return 0;
|
||||
int r = 1;
|
||||
while (y) {
|
||||
if (y & 1)
|
||||
r *= x;
|
||||
y >>= 1;
|
||||
x *= x;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
//%
|
||||
int random(int max) {
|
||||
if (max == INT_MIN)
|
||||
return -microbit_random(INT_MAX);
|
||||
else if (max < 0)
|
||||
return -microbit_random(-max);
|
||||
else if (max == 0)
|
||||
return 0;
|
||||
else
|
||||
return microbit_random(max);
|
||||
}
|
||||
|
||||
//%
|
||||
int sqrt(int x)
|
||||
{
|
||||
return ::sqrt(x);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Array_ {
|
||||
//%
|
||||
RefCollection *mk(uint32_t flags)
|
||||
{
|
||||
return new RefCollection(flags);
|
||||
}
|
||||
//%
|
||||
int length(RefCollection *c) { return c->length(); }
|
||||
//%
|
||||
void setLength(RefCollection *c, int newLength) { c->setLength(newLength); }
|
||||
//%
|
||||
void push(RefCollection *c, uint32_t x) { c->push(x); }
|
||||
//%
|
||||
uint32_t pop(RefCollection *c) { return c->pop(); }
|
||||
//%
|
||||
uint32_t getAt(RefCollection *c, int x) { return c->getAt(x); }
|
||||
//%
|
||||
void setAt(RefCollection *c, int x, uint32_t y) { c->setAt(x, y); }
|
||||
//%
|
||||
uint32_t removeAt(RefCollection *c, int x) { return c->removeAt(x); }
|
||||
//%
|
||||
void insertAt(RefCollection *c, int x, uint32_t value) { c->insertAt(x, value); }
|
||||
//%
|
||||
int indexOf(RefCollection *c, uint32_t x, int start) { return c->indexOf(x, start); }
|
||||
//%
|
||||
int removeElement(RefCollection *c, uint32_t x) { return c->removeElement(x); }
|
||||
}
|
||||
|
||||
|
||||
// Import some stuff directly
|
||||
namespace pxt {
|
||||
//%
|
||||
void registerWithDal(int id, int event, Action a);
|
||||
//%
|
||||
uint32_t runAction3(Action a, int arg0, int arg1, int arg2);
|
||||
//%
|
||||
uint32_t runAction2(Action a, int arg0, int arg1);
|
||||
//%
|
||||
uint32_t runAction1(Action a, int arg0);
|
||||
//%
|
||||
uint32_t runAction0(Action a);
|
||||
//%
|
||||
Action mkAction(int reflen, int totallen, int startptr);
|
||||
//%
|
||||
RefRecord* mkClassInstance(int offset);
|
||||
//%
|
||||
void RefRecord_destroy(RefRecord *r);
|
||||
//%
|
||||
void RefRecord_print(RefRecord *r);
|
||||
//%
|
||||
void debugMemLeaks();
|
||||
//%
|
||||
int incr(uint32_t e);
|
||||
//%
|
||||
void decr(uint32_t e);
|
||||
//%
|
||||
uint32_t *allocate(uint16_t sz);
|
||||
//%
|
||||
int templateHash();
|
||||
//%
|
||||
int programHash();
|
||||
//%
|
||||
void *ptrOfLiteral(int offset);
|
||||
//%
|
||||
int getNumGlobals();
|
||||
|
||||
//%
|
||||
uint32_t programSize() {
|
||||
return bytecode[17] * 2;
|
||||
}
|
||||
|
||||
//%
|
||||
uint32_t afterProgramPage() {
|
||||
uint32_t ptr = (uint32_t)&bytecode[0];
|
||||
ptr += programSize();
|
||||
if (ptr % PAGE_SIZE != 0)
|
||||
ptr = (ptr & ~(PAGE_SIZE-1)) + PAGE_SIZE;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxtrt {
|
||||
//%
|
||||
uint32_t ldloc(RefLocal *r) {
|
||||
return r->v;
|
||||
}
|
||||
|
||||
//%
|
||||
uint32_t ldlocRef(RefRefLocal *r) {
|
||||
uint32_t tmp = r->v;
|
||||
incr(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//%
|
||||
void stloc(RefLocal *r, uint32_t v) {
|
||||
r->v = v;
|
||||
}
|
||||
|
||||
//%
|
||||
void stlocRef(RefRefLocal *r, uint32_t v) {
|
||||
decr(r->v);
|
||||
r->v = v;
|
||||
}
|
||||
|
||||
//%
|
||||
RefLocal *mkloc() {
|
||||
return new RefLocal();
|
||||
}
|
||||
|
||||
//%
|
||||
RefRefLocal *mklocRef() {
|
||||
return new RefRefLocal();
|
||||
}
|
||||
|
||||
// All of the functions below unref() self. This is for performance reasons -
|
||||
// the code emitter will not emit the unrefs for them.
|
||||
|
||||
//%
|
||||
uint32_t ldfld(RefRecord *r, int idx) {
|
||||
auto tmp = r->ld(idx);
|
||||
r->unref();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//%
|
||||
uint32_t ldfldRef(RefRecord *r, int idx) {
|
||||
auto tmp = r->ldref(idx);
|
||||
r->unref();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//%
|
||||
void stfld(RefRecord *r, int idx, uint32_t val) {
|
||||
r->st(idx, val);
|
||||
r->unref();
|
||||
}
|
||||
|
||||
//%
|
||||
void stfldRef(RefRecord *r, int idx, uint32_t val) {
|
||||
r->stref(idx, val);
|
||||
r->unref();
|
||||
}
|
||||
|
||||
// Store a captured local in a closure. It returns the action, so it can be chained.
|
||||
//%
|
||||
RefAction *stclo(RefAction *a, int idx, uint32_t v)
|
||||
{
|
||||
//DBG("STCLO "); a->print(); DBG("@%d = %p\n", idx, (void*)v);
|
||||
a->stCore(idx, v);
|
||||
return a;
|
||||
}
|
||||
|
||||
//%
|
||||
void panic(int code)
|
||||
{
|
||||
microbit_panic(code);
|
||||
}
|
||||
|
||||
//%
|
||||
int stringToBool(StringData *s) {
|
||||
if (s == NULL) return 0;
|
||||
if (s->len == 0) {
|
||||
s->decr();
|
||||
return 0;
|
||||
}
|
||||
s->decr();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//%
|
||||
StringData* emptyToNull(StringData *s) {
|
||||
if (!s || s->len == 0)
|
||||
return NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
//%
|
||||
int ptrToBool(uint32_t p) {
|
||||
if (p) {
|
||||
decr(p);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//%
|
||||
RefMap *mkMap() {
|
||||
return new RefMap();
|
||||
}
|
||||
|
||||
//%
|
||||
uint32_t mapGet(RefMap *map, uint32_t key) {
|
||||
int i = map->findIdx(key);
|
||||
if (i < 0) {
|
||||
map->unref();
|
||||
return 0;
|
||||
}
|
||||
uint32_t r = map->data[i].val;
|
||||
map->unref();
|
||||
return r;
|
||||
}
|
||||
|
||||
//%
|
||||
uint32_t mapGetRef(RefMap *map, uint32_t key) {
|
||||
int i = map->findIdx(key);
|
||||
if (i < 0) {
|
||||
map->unref();
|
||||
return 0;
|
||||
}
|
||||
uint32_t r = incr(map->data[i].val);
|
||||
map->unref();
|
||||
return r;
|
||||
}
|
||||
|
||||
//%
|
||||
void mapSet(RefMap *map, uint32_t key, uint32_t val) {
|
||||
int i = map->findIdx(key);
|
||||
if (i < 0) {
|
||||
map->data.push_back({
|
||||
key << 1,
|
||||
val
|
||||
});
|
||||
} else {
|
||||
if (map->data[i].key & 1) {
|
||||
decr(map->data[i].val);
|
||||
map->data[i].key = key << 1;
|
||||
}
|
||||
map->data[i].val = val;
|
||||
}
|
||||
map->unref();
|
||||
}
|
||||
|
||||
//%
|
||||
void mapSetRef(RefMap *map, uint32_t key, uint32_t val) {
|
||||
int i = map->findIdx(key);
|
||||
if (i < 0) {
|
||||
map->data.push_back({
|
||||
(key << 1) | 1,
|
||||
val
|
||||
});
|
||||
} else {
|
||||
if (map->data[i].key & 1) {
|
||||
decr(map->data[i].val);
|
||||
} else {
|
||||
map->data[i].key = (key << 1) | 1;
|
||||
}
|
||||
map->data[i].val = val;
|
||||
}
|
||||
map->unref();
|
||||
}
|
||||
|
||||
//
|
||||
// Debugger
|
||||
//
|
||||
|
||||
//%
|
||||
void* getGlobalsPtr() {
|
||||
return globals;
|
||||
}
|
||||
|
||||
//%
|
||||
void runtimeWarning(StringData *s) {
|
||||
// noop for now
|
||||
}
|
||||
}
|
12
libs/core/dal.d.ts
vendored
@ -420,11 +420,11 @@ declare const enum DAL {
|
||||
MICROBIT_ACCELEROMETER_EVT_FACE_UP = 5,
|
||||
MICROBIT_ACCELEROMETER_EVT_FACE_DOWN = 6,
|
||||
MICROBIT_ACCELEROMETER_EVT_FREEFALL = 7,
|
||||
MICROBIT_ACCELEROMETER_EVT_2G = 8,
|
||||
MICROBIT_ACCELEROMETER_EVT_3G = 9,
|
||||
MICROBIT_ACCELEROMETER_EVT_6G = 10,
|
||||
MICROBIT_ACCELEROMETER_EVT_8G = 11,
|
||||
MICROBIT_ACCELEROMETER_EVT_SHAKE = 12,
|
||||
// MICROBIT_ACCELEROMETER_EVT_2G = 8,
|
||||
MICROBIT_ACCELEROMETER_EVT_3G = 8,
|
||||
MICROBIT_ACCELEROMETER_EVT_6G = 9,
|
||||
MICROBIT_ACCELEROMETER_EVT_8G = 10,
|
||||
MICROBIT_ACCELEROMETER_EVT_SHAKE = 11,
|
||||
MICROBIT_ACCELEROMETER_REST_TOLERANCE = 200,
|
||||
MICROBIT_ACCELEROMETER_TILT_TOLERANCE = 200,
|
||||
MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE = 400,
|
||||
@ -641,4 +641,4 @@ declare const enum DAL {
|
||||
// built/yt/yotta_modules/microbit-dal/inc/types/MicroBitImage.h
|
||||
// built/yt/yotta_modules/microbit-dal/inc/types/PacketBuffer.h
|
||||
// built/yt/yotta_modules/microbit-dal/inc/types/RefCounted.h
|
||||
}
|
||||
}
|
111
libs/core/enums.d.ts
vendored
@ -1,4 +1,30 @@
|
||||
// Auto-generated. Do not edit.
|
||||
|
||||
|
||||
declare const enum NumberFormat {
|
||||
Int8LE = 1,
|
||||
UInt8LE = 2,
|
||||
Int16LE = 3,
|
||||
UInt16LE = 4,
|
||||
Int32LE = 5,
|
||||
Int8BE = 6,
|
||||
UInt8BE = 7,
|
||||
Int16BE = 8,
|
||||
UInt16BE = 9,
|
||||
Int32BE = 10,
|
||||
|
||||
UInt32LE = 11,
|
||||
UInt32BE = 12,
|
||||
Float32LE = 13,
|
||||
Float64LE = 14,
|
||||
Float32BE = 15,
|
||||
Float64BE = 16,
|
||||
}
|
||||
|
||||
|
||||
declare const enum PerfCounters {
|
||||
GC = 0,
|
||||
}
|
||||
declare namespace images {
|
||||
}
|
||||
declare namespace basic {
|
||||
@ -70,57 +96,68 @@ declare namespace basic {
|
||||
* Raised when shaken
|
||||
*/
|
||||
//% block=shake
|
||||
Shake = 12, // MICROBIT_ACCELEROMETER_EVT_SHAKE
|
||||
//% jres=gestures.shake
|
||||
Shake = 11, // MICROBIT_ACCELEROMETER_EVT_SHAKE
|
||||
/**
|
||||
* Raised when the logo is upward and the screen is vertical
|
||||
*/
|
||||
//% block="logo up"
|
||||
//% jres=gestures.tiltforward
|
||||
LogoUp = 1, // MICROBIT_ACCELEROMETER_EVT_TILT_UP
|
||||
/**
|
||||
* Raised when the logo is downward and the screen is vertical
|
||||
*/
|
||||
//% block="logo down"
|
||||
//% jres=gestures.tiltbackwards
|
||||
LogoDown = 2, // MICROBIT_ACCELEROMETER_EVT_TILT_DOWN
|
||||
/**
|
||||
* Raised when the screen is pointing down and the board is horizontal
|
||||
*/
|
||||
//% block="screen up"
|
||||
//% jres=gestures.frontsideup
|
||||
ScreenUp = 5, // MICROBIT_ACCELEROMETER_EVT_FACE_UP
|
||||
/**
|
||||
* Raised when the screen is pointing up and the board is horizontal
|
||||
*/
|
||||
//% block="screen down"
|
||||
//% jres=gestures.backsideup
|
||||
ScreenDown = 6, // MICROBIT_ACCELEROMETER_EVT_FACE_DOWN
|
||||
/**
|
||||
* Raised when the screen is pointing left
|
||||
*/
|
||||
//% block="tilt left"
|
||||
//% jres=gestures.tiltleft
|
||||
TiltLeft = 3, // MICROBIT_ACCELEROMETER_EVT_TILT_LEFT
|
||||
/**
|
||||
* Raised when the screen is pointing right
|
||||
*/
|
||||
//% block="tilt right"
|
||||
//% jres=gestures.tiltright
|
||||
TiltRight = 4, // MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT
|
||||
/**
|
||||
* Raised when the board is falling!
|
||||
*/
|
||||
//% block="free fall"
|
||||
//% jres=gestures.freefall
|
||||
FreeFall = 7, // MICROBIT_ACCELEROMETER_EVT_FREEFALL
|
||||
/**
|
||||
* Raised when a 3G shock is detected
|
||||
*/
|
||||
//% block="3g"
|
||||
ThreeG = 9, // MICROBIT_ACCELEROMETER_EVT_3G
|
||||
//% jres=gestures.impact3g
|
||||
ThreeG = 8, // MICROBIT_ACCELEROMETER_EVT_3G
|
||||
/**
|
||||
* Raised when a 6G shock is detected
|
||||
*/
|
||||
//% block="6g"
|
||||
SixG = 10, // MICROBIT_ACCELEROMETER_EVT_6G
|
||||
//% jres=gestures.impact6g
|
||||
SixG = 9, // MICROBIT_ACCELEROMETER_EVT_6G
|
||||
/**
|
||||
* Raised when a 8G shock is detected
|
||||
*/
|
||||
//% block="8g"
|
||||
EightG = 11, // MICROBIT_ACCELEROMETER_EVT_8G
|
||||
//% jres=gestures.impact8g
|
||||
EightG = 10, // MICROBIT_ACCELEROMETER_EVT_8G
|
||||
}
|
||||
|
||||
|
||||
@ -230,8 +267,6 @@ declare namespace input {
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MICROBIT_ID_IO_P20 = 25, // MICROBIT_ID_IO_P20
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MICROBIT_ID_IO_P21 = 50, // MICROBIT_ID_IO_P21
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MES_DEVICE_INFO_ID = 1103, // MES_DEVICE_INFO_ID
|
||||
//% blockIdentity="control.eventSourceId"
|
||||
MES_SIGNAL_STRENGTH_ID = 1101, // MES_SIGNAL_STRENGTH_ID
|
||||
@ -366,12 +401,24 @@ declare namespace input {
|
||||
//% blockIdentity="control.eventValueId"
|
||||
MES_REMOTE_CONTROL_EVT_VOLUMEUP = 8, // MES_REMOTE_CONTROL_EVT_VOLUMEUP
|
||||
}
|
||||
|
||||
|
||||
declare const enum EventFlags {
|
||||
//%
|
||||
QueueIfBusy = 0x0010, // MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY
|
||||
//%
|
||||
DropIfBusy = 0x0020, // MESSAGE_BUS_LISTENER_DROP_IF_BUSY
|
||||
//%
|
||||
Reentrant = 0x0008, // MESSAGE_BUS_LISTENER_REENTRANT
|
||||
}
|
||||
declare namespace control {
|
||||
}
|
||||
|
||||
|
||||
declare const enum DisplayMode {
|
||||
//% block="black and white"
|
||||
BlackAndWhite = 0, // DISPLAY_MODE_BLACK_AND_WHITE
|
||||
//% blockHidden=true
|
||||
BackAndWhite = 0, // DISPLAY_MODE_BLACK_AND_WHITE
|
||||
//% block="greyscale"
|
||||
Greyscale = 1, // DISPLAY_MODE_GREYSCALE
|
||||
@ -435,7 +482,9 @@ declare namespace motors {
|
||||
|
||||
|
||||
declare const enum PulseValue {
|
||||
//% block=high
|
||||
High = 4, // MICROBIT_PIN_EVT_PULSE_HI
|
||||
//% block=low
|
||||
Low = 5, // MICROBIT_PIN_EVT_PULSE_LO
|
||||
}
|
||||
|
||||
@ -463,12 +512,17 @@ declare namespace motors {
|
||||
|
||||
|
||||
declare const enum SerialPin {
|
||||
C16 = 9, // MICROBIT_ID_IO_P2
|
||||
C17 = 15, // MICROBIT_ID_IO_P8
|
||||
P0 = 19, // MICROBIT_ID_IO_P12
|
||||
P1 = 7, // MICROBIT_ID_IO_P0
|
||||
P2 = 8, // MICROBIT_ID_IO_P1
|
||||
P3 = 23, // MICROBIT_ID_IO_P16
|
||||
P0 = 7, // MICROBIT_ID_IO_P0
|
||||
P1 = 8, // MICROBIT_ID_IO_P1
|
||||
P2 = 9, // MICROBIT_ID_IO_P2
|
||||
P8 = 15, // MICROBIT_ID_IO_P8
|
||||
P12 = 19, // MICROBIT_ID_IO_P12
|
||||
P13 = 20, // MICROBIT_ID_IO_P13
|
||||
P14 = 21, // MICROBIT_ID_IO_P14
|
||||
P15 = 22, // MICROBIT_ID_IO_P15
|
||||
P16 = 23, // MICROBIT_ID_IO_P16
|
||||
USB_TX = 1001,
|
||||
USB_RX = 1002,
|
||||
}
|
||||
|
||||
|
||||
@ -476,9 +530,25 @@ declare namespace motors {
|
||||
//% block=115200
|
||||
BaudRate115200 = 115200,
|
||||
//% block=57600
|
||||
BaudRate56700 = 57600,
|
||||
BaudRate57600 = 57600,
|
||||
//% block=38400
|
||||
BaudRate38400 = 38400,
|
||||
//% block=31250
|
||||
BaudRate31250 = 31250,
|
||||
//% block=28800
|
||||
BaudRate28800 = 28800,
|
||||
//% block=19200
|
||||
BaudRate19200 = 19200,
|
||||
//% block=14400
|
||||
BaudRate14400 = 14400,
|
||||
//% block=9600
|
||||
BaudRate9600 = 9600,
|
||||
//% block=4800
|
||||
BaudRate4800 = 4800,
|
||||
//% block=2400
|
||||
BaudRate2400 = 2400,
|
||||
//% block=1200
|
||||
BaudRate1200 = 1200,
|
||||
}
|
||||
|
||||
|
||||
@ -499,19 +569,4 @@ declare namespace motors {
|
||||
declare namespace serial {
|
||||
}
|
||||
|
||||
|
||||
declare const enum NumberFormat {
|
||||
Int8LE = 1,
|
||||
UInt8LE = 2,
|
||||
Int16LE = 3,
|
||||
UInt16LE = 4,
|
||||
Int32LE = 5,
|
||||
Int8BE = 6,
|
||||
UInt8BE = 7,
|
||||
Int16BE = 8,
|
||||
UInt16BE = 9,
|
||||
Int32BE = 10,
|
||||
// UInt32,
|
||||
}
|
||||
|
||||
// Auto-generated. Do not edit. Really.
|
||||
|
@ -168,9 +168,10 @@ namespace game {
|
||||
|
||||
/**
|
||||
* Sets the current life value
|
||||
* @param value TODO
|
||||
* @param value current life value
|
||||
*/
|
||||
//% weight=10
|
||||
//% weight=10 help=game/set-life
|
||||
//% blockId=game_set_life block="set life %value" blockGap=8
|
||||
export function setLife(value: number): void {
|
||||
_life = Math.max(0, value);
|
||||
if (_life <= 0) {
|
||||
@ -179,10 +180,11 @@ namespace game {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds life points to the current life
|
||||
* @param lives TODO
|
||||
* Add life points to the current life amount
|
||||
* @param lives amount of lives to add
|
||||
*/
|
||||
//% weight=10
|
||||
//% weight=10 help=game/add-life
|
||||
//% blockId=game_add_life block="add life %lives" blockGap=8
|
||||
export function addLife(lives: number): void {
|
||||
setLife(_life + lives);
|
||||
}
|
||||
@ -200,14 +202,16 @@ namespace game {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes some life
|
||||
* @param life TODO
|
||||
* Remove some life
|
||||
* @param life amount of life to remove
|
||||
*/
|
||||
//% weight=10
|
||||
//% weight=10 help=game/remove-life
|
||||
//% parts="ledmatrix"
|
||||
//% blockId=game_remove_life block="remove life %life" blockGap=8
|
||||
export function removeLife(life: number): void {
|
||||
setLife(_life - life);
|
||||
if (!_paused)
|
||||
if (!_paused && !_backgroundAnimation) {
|
||||
_backgroundAnimation = true;
|
||||
control.inBackground(() => {
|
||||
led.stopAnimation();
|
||||
basic.showAnimation(`1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0
|
||||
@ -215,7 +219,9 @@ namespace game {
|
||||
0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
|
||||
0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0
|
||||
1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0`, 40);
|
||||
_backgroundAnimation = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -247,12 +253,12 @@ namespace game {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating if the game is still running. Returns `false` if game over.
|
||||
* Indicates if the game is still running. Returns `false` if the game is over or paused.
|
||||
*/
|
||||
//% weight=10
|
||||
//% weight=5 help=game/is-running
|
||||
//% blockId=game_isrunning block="is running" blockGap=8
|
||||
export function isRunning(): boolean {
|
||||
let running: boolean;
|
||||
return !_isGameOver;
|
||||
return !_isGameOver && !_paused && !!_img;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -267,8 +273,10 @@ namespace game {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the game is display the game over sequence.
|
||||
* Indicates if the game is over and displaying the game over sequence.
|
||||
*/
|
||||
//% weight=7 help=game/is-game-over
|
||||
//% blockId=game_isgameover block="is game over" blockGap=8
|
||||
export function isGameOver(): boolean {
|
||||
return _isGameOver;
|
||||
}
|
||||
@ -276,7 +284,8 @@ namespace game {
|
||||
/**
|
||||
* Indicates if the game rendering is paused to allow other animations
|
||||
*/
|
||||
//%
|
||||
//% weight=6 help=game/is-paused
|
||||
//% blockId=game_ispaused block="is paused" blockGap=8
|
||||
export function isPaused(): boolean {
|
||||
return _paused;
|
||||
}
|
||||
@ -396,7 +405,7 @@ namespace game {
|
||||
|
||||
/**
|
||||
* If touching the edge of the stage and facing towards it, then turn away.
|
||||
* @param this TODO
|
||||
* @param this the sprite to check for bounce
|
||||
*/
|
||||
//% weight=18 help=game/if-on-edge-bounce
|
||||
//% blockId=game_sprite_bounce block="%sprite|if on edge, bounce"
|
||||
@ -448,7 +457,7 @@ namespace game {
|
||||
|
||||
/**
|
||||
* Turn the sprite
|
||||
* @param this TODO
|
||||
* @param this the sprite to trun
|
||||
* @param direction left or right
|
||||
* @param degrees angle in degrees to turn, eg: 45, 90, 180, 135
|
||||
*/
|
||||
@ -463,7 +472,7 @@ namespace game {
|
||||
|
||||
/**
|
||||
* Turn to the right (clockwise)
|
||||
* @param this TODO
|
||||
* @param this the sprite to turn
|
||||
* @param degrees TODO
|
||||
*/
|
||||
public turnRight(degrees: number): void {
|
||||
@ -472,7 +481,7 @@ namespace game {
|
||||
|
||||
/**
|
||||
* Turn to the left (counter-clockwise)
|
||||
* @param this TODO
|
||||
* @param this the sprite to turn
|
||||
* @param degrees TODO
|
||||
*/
|
||||
public turnLeft(degrees: number): void {
|
||||
@ -532,12 +541,12 @@ namespace game {
|
||||
|
||||
/**
|
||||
* Set the direction of the current sprite, rounded to the nearest multiple of 45
|
||||
* @param this TODO
|
||||
* @param degrees TODO
|
||||
* @param this the sprite to set direction for
|
||||
* @param degrees new direction in degrees
|
||||
*/
|
||||
//% parts="ledmatrix"
|
||||
public setDirection(degrees: number): void {
|
||||
this._dir = ((degrees / 45) % 8) * 45;
|
||||
this._dir = (Math.floor(degrees / 45) % 8) * 45;
|
||||
if (this._dir <= -180) {
|
||||
this._dir = this._dir + 360;
|
||||
} else if (this._dir > 180) {
|
||||
@ -608,23 +617,23 @@ namespace game {
|
||||
|
||||
/**
|
||||
* Reports true if sprite has the same position as specified sprite
|
||||
* @param this TODO
|
||||
* @param other TODO
|
||||
* @param this the sprite to check overlap or touch
|
||||
* @param other the other sprite to check overlap or touch
|
||||
*/
|
||||
//% weight=20 help=game/is-touching
|
||||
//% blockId=game_sprite_touching_sprite block="%sprite|touching %other|?" blockGap=8
|
||||
//% blockId=game_sprite_touching_sprite block="is %sprite|touching %other" blockGap=8
|
||||
public isTouching(other: LedSprite): boolean {
|
||||
return this._enabled && other._enabled && this._x == other._x && this._y == other._y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports true if sprite is touching an edge
|
||||
* @param this TODO
|
||||
* @param this the sprite to check for an edge contact
|
||||
*/
|
||||
//% weight=19 help=game/is-touching-edge
|
||||
//% blockId=game_sprite_touching_edge block="%sprite|touching edge?" blockGap=8
|
||||
//% blockId=game_sprite_touching_edge block="is %sprite|touching edge" blockGap=8
|
||||
public isTouchingEdge(): boolean {
|
||||
return this._x == 0 || this._x == 4 || this._y == 0 || this._y == 4;
|
||||
return this._enabled && (this._x == 0 || this._x == 4 || this._y == 0 || this._y == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -686,14 +695,23 @@ namespace game {
|
||||
* Deletes the sprite from the game engine. The sprite will no longer appear on the screen or interact with other sprites.
|
||||
* @param this sprite to delete
|
||||
*/
|
||||
//% weight=59 help=game/delete
|
||||
//% blockId="game_delete_sprite" block="delete %this"
|
||||
//% weight=59 blockGap=8 help=game/delete
|
||||
//% blockId="game_delete_sprite" block="delete %this(sprite)"
|
||||
public delete(): void {
|
||||
this._enabled = false;
|
||||
if (_sprites.removeElement(this))
|
||||
plot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports whether the sprite has been deleted from the game engine.
|
||||
*/
|
||||
//% weight=58 help=game/is-deleted
|
||||
//% blockId="game_sprite_is_deleted" block="is %sprite|deleted"
|
||||
public isDeleted(): boolean {
|
||||
return !this._enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blink duration interval in millisecond.
|
||||
* @param sprite TODO
|
||||
@ -717,7 +735,6 @@ namespace game {
|
||||
* @param this TODO
|
||||
*/
|
||||
public blink(): number {
|
||||
let r: number;
|
||||
return this._blink;
|
||||
}
|
||||
|
||||
@ -728,7 +745,7 @@ namespace game {
|
||||
if (ps._brightness > 0) {
|
||||
let r = 0;
|
||||
if (ps._blink > 0) {
|
||||
r = (now / ps._blink) % 2;
|
||||
r = Math.floor(now / ps._blink) % 2;
|
||||
}
|
||||
if (r == 0) {
|
||||
_img.setPixelBrightness(ps._x, ps._y, _img.pixelBrightness(ps._x, ps._y) + ps._brightness);
|
||||
@ -766,7 +783,7 @@ namespace game {
|
||||
}
|
||||
// ensure greyscale mode
|
||||
const dm = led.displayMode();
|
||||
if (dm != DisplayMode.Greyscale)
|
||||
if (dm != DisplayMode.Greyscale)
|
||||
led.setDisplayMode(DisplayMode.Greyscale);
|
||||
// render sprites
|
||||
const now = input.runningTime();
|
||||
@ -775,9 +792,6 @@ namespace game {
|
||||
_sprites[i]._plot(now);
|
||||
}
|
||||
_img.plotImage(0);
|
||||
// restore previous display mode
|
||||
if (dm != DisplayMode.Greyscale)
|
||||
led.setDisplayMode(dm);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -789,3 +803,4 @@ namespace game {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
39
libs/core/gestures.jres
Normal file
@ -1,17 +1,10 @@
|
||||
namespace console {
|
||||
export function log(msg: string) {
|
||||
serial.writeString(msg);
|
||||
serial.writeString("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
namespace Math {
|
||||
/**
|
||||
* Generates a `true` or `false` value randomly, just like flipping a coin.
|
||||
*/
|
||||
//% blockId=logic_random block="pick random true or false"
|
||||
//% help=math/random-boolean color=230
|
||||
//% help=math/random-boolean weight=0 color=712672
|
||||
export function randomBoolean(): boolean {
|
||||
return Math.random(2) == 0;
|
||||
return Math.randomRange(0, 1) === 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
126
libs/core/icons.jres
Normal file
@ -0,0 +1,126 @@
|
||||
{
|
||||
"*": {
|
||||
"namespace": "icons",
|
||||
"dataEncoding": "base64"
|
||||
},
|
||||
"heart": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"smallheart": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE5ElEQVR4nO3dMY5URxQF0NdGTtAQY3sB3gALsNgTJBapneA9WXbOBryAARIiRABBO5i2Ru2hLv9P9W9V9ZyT8nveVfXcgZGaelUAAADAEHbf+POrqnpaVY+r6vsTz/5SVZ+q6n1Vfbzn15BPvvtalC8V5Ieq+unEoVquq+rdytfId0u+Ps183zVecFXnC1eHWVcrnpfvmHx9mvlaBXm6XZamNTPl65sp38KZrYI83jBIy5qZ8vXNlG/hzFZBTv0L0RJrZsrXN1O+hTNbBQFKQSBSEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCFoF+XLWFOtnytc3U76FM1sF+bRhkJY1M+XrmynfwpmtgrzfMEjLmpny9c2Ub+HMR42HP1fVvqqebBbn2HVVfVjxvHzH5OvTzOfy6jb5+jyEfAAAAAAAAADwwEz9UZP9fv9LVb2sqmd1szb4lN5V1Zuqer3b7f6659dwfpOf37R70vf7/a9V9ds2cY5HVdWr3W73+8rXOb/DqJr4/FoFuaqqnzeL83X/1MKfhIeffH/Wt/8GPJV9VT1f8ZPQ+f1vZE16frPuSX9Z53tz6zDrxYrnnd+xac9v1j3pzzZLcZqZzq9v5jDnN+ue9FP/QrnEjyuedX53TXl+bjWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAhm3ZO+6g6oE3m74lnnd9eU5zfrnvQ3m6U4zUzn1zdzmPObdU/667q5jOxc9oeZSzm/Y9OeX6sgH+vmOsZzua4V98sebuh7Ved5k/+7OvPvFa9xfremPr9LuLz6Rd1cSrbm3qUl3tbNPwv+mPny5cT52ZMOAAAAAAAAAOtcwkdNht3zLZ896adycXu+5bsdVfakn8TF7PmW7+7Isie92yXt+ZbvmD3pJ3BJe77l65s5zPefPenLrfn/EvLdZU86XBoFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgsCd9uTV7vuW7y570Tpe051u+vpnDfP/Zk77M2j3f8h2zJ73TRe35lu+IPen3dPF7vuWzJx0AAAAAAAAALsvUHzWpwfPZQz7/+zvtnvQaPJ895EemfX+n3JNeg+ezh/yrpnx/Z92TPno+e8j7Zg6Tb9Y96aPns4e8b+Yw+Wbdkz56PnvI+2YOk8+tJhAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCwax70kfPZw9538xh8s26J330fPaQ980cJt+se9JHz2cPed/MYfJNuSe9Bs9nD/kd076/Lq9uu/g97jX4+dX4+QAAAAAAAADggfFRkzb5+lxEPnvSl5Gvz7T5Wp/mvarzhavDrKsVz8t3TL4+zXz2pG8zU76+mcPksyd9m5ny9c0cJp896dvMlK9v5jD53GoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBDYk77NTPn6Zg6Tz570bWbK1zdzmHz2pG8zU76+mcPke9R4+HPd7N9+slmcY9dV9WHF8/Idk69PM5/Lq9vk6/MQ8gEAAADn8i9uSXT/dv6GSgAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"yes": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHUlEQVR4nO3dQY5UZRQF4FsaJ6Qdoy7ADbAA455gYpjqBPdkdM4GXADCxBFhIINy0G2k0u+efsVfr/ir+L4h3e09eckRiOU7VQAAAMAUdg98/aaqHlfVo6r66sS331fVu6p6U1VvP/KfIZ98H2tVvlSQb6rquxOH6ryqqtdH/ox8/5NvTJvvi+YHbup84eru1s0R3y/fIfnGtPm6gjzeLkvrmJvyjd2Ub+XNriCPNgzSOeamfGM35Vt5syvIqf9CtMYxN+UbuynfyptdQYBSEIgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEgq4g78+a4vib8o3dlG/lza4g7zYM0jnmpnxjN+VbebMryJsNg3SOuSnf2E35Vt78svnmf6pqX1Vfbxbn0Kuq+vuI75fvkHxj2nxeXt2Tb8znkA8AAAAAAAAAPjM+atKTb8xwvv1+/0NVPauqJ3U7C31Kr6vqZVW92O12v3ffZCd9HfnGHJ1vv9//VFU/bxPn8FRVPd/tdr8sfbEryE1Vfb9ZpGV/1vp/08h339Xku/ud47d6+E84p7Kvqh+Xfiexk77NTfnGbj6r85Wj7m49XfqCnfRtbso3dvPJZimOvGknfZub8o3dPPVfyNf4dukXvdUEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSCwk77NTfnGbh77jq9T+GvpF+2kb3NTvrGbLzdLceRNO+nb3JRv7OaLun2Z27ns727e0xXkbd2+LvJcXtVx72+V79BV5bt7w+HzOk9J/nv16B+LWR744alfblzyXXW+u1eQPq3bl7otvrdqwF91+8eqX9PLqwEAAAAAAACAD/moSe/q882wQ/6AT/787KSvc3X5ZtkhD6Z4fnbS17uafDPtkDemeX520re5OXu+aXbIG9M8Pzvp29ycPd80O+SNaZ6fnfRtbs6eb5od8sY0z89bTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAjvp29ycPd80O+SNaZ6fnfRtbs6eb5od8sY0z89O+jY3Z883zQ55Y5rnZyd9navKN9MOeWOa5+fl1b2rz3cBO+RTPz8AAAAAAAAA+PzEj5rY0bZDPuAqPqrTFsSO9gE75GMudmd+sSB2tBfZIR9zkTvz3cfd7WiP3fT8xm5Ok68riB3tsZue39jNafJ1BbGjPXbT8xu7OU0+bzWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAi6gtjRHrvp+Y3dnCZfVxA72mM3Pb+xm9Pk6wpiR3vspuc3dnOafIsFsaN9jx3yMRe7M7/m5dV2tO2Qf4yreHk1AAAAAAAAAPChh4Ymp/5P/XbIr/6jHJ88XyrIFDvVHTvkBy52hzyYIl9XkGl2qpfYIV90kTvkjWnydf8/yDQ71Q075GM35Vt5syvINDvVDTvkYzflW3mzK8g0O9UNO+RjN+VbedNbTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEgq4g0+xUN+yQj92Ub+XNriDT7FQ37JCP3ZRv5c2uINPsVDfskI/dlG/lza4g0+xUL7FDfs/F7pA3psl3DS+vtkN+wS+HfsDs+QAAAIBz+RdDw2v5jDe3GQAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"no": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFCElEQVR4nO3dMY5URxQF0NeWnCBysBfgDbAAy3uCxCK1E7wny87ZgBcAJkckBO1g2sJN/7r+f6p7VPXnnJQZ3lNNXRBSU7cKAAAAGMIh/eLxePyxql5V1Yuqen7l2X9X1duqenM4HP645+/xtKqeVdWTqvr2WoudfK6qT1X1oao+3vP3sF/HfiPcv2ZAjsfjz1X1y5WXWhxVVa8Ph8OvG7/veVV9f4N9lryruwPdwn5fbN5vlPu3GJBTcn9v/foNHKvqpw1/kzytqh9uuM+Sv2r9n4T2u7R6v5Hu3zeNb3hVD7dcnWa93PD1z261yJVm2q9v5jD3rxWQF7fbpWnLzCc32+I6M+3XN3OY+9cKyLX/QbTGdxu+9tr/oLz2TPv1zRzm/rUCApSAQCQgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQtAKy9Y2la3i/4Ws/32yL68y0X9/MYe5fKyBvb7hIy5aZn262xXVm2q9v5jD3rxWQN3X3mNZDOZ5mrvXhVotcaab9+mYOc/8WA3J6Ye51PcyS/z79+OeG7/lYd89ZPpR3te19Wfud27TfSPdvzePVL+vuUa0t71at8b7u/lr7zePV97L7/Sa4fwAAAAAAAADwyPxfUeIMH0XQ4+787mPV+aWA6NE+jaod9rg7vzPN82sFRI/2VyNrRz3uzm/R4vm1/j+IHu1ze+txd34rZ7YCoke7b6bz65s5zPm1AqJH+9Keetyd38qZXjWBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAhaAdGjfWlPPe7Ob+XMVkD0aPfNdH59M4c5v1ZA9Gif21uPu/NbObMVED3aX+yux935XWie3x4erx65R9v57fj8AAAAAAAAAODxmfqjJjX4fnrI5//5TtuTXoPvp4f8zLQ/3yl70mvw/fSQL5ry5ztrT/ro++kh75s5zH6z9qSPvp8e8r6Zw+w3a0/66PvpIe+bOcx+XjWBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAhm7UkffT895H0zh9lv1p700ffTQ943c5j9Zu1JH30/PeR9M4fZb8qe9Bp8Pz3kF6b9+Xq8uk0PeZ/d/3wBAAAAAAAA4PGZ+qMmesidX4d996TrIT/j/PrsqyddD/ki59dnVz3pesj7Zjq/lTNn7UnXQ9430/mtnDlrT7oe8r6Zzm/lTK+aQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEs/ak6yHvm+n8Vs6ctSddD3nfTOe3cuasPel6yPtmOr+VM6fsSddDfsH59dlnT7oecufXQU86AAAAAAAAAGwWP2qiR7v7owj2m7zHvRkQPdpnNveQl/3+a9oe98WA6NFetLqHvOy3ZMoe99bH3fVo9820X9/MYe5fKyB6tPtm2q9v5jD3rxUQPdp9M+3XN3OY++dVEwgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBoBUQPdp9M+3XN3OY+9cKiB7tvpn265s5zP1rBUSPdt9M+/XNHOb+LQZEj/aFTT3kZb+vTdvjvubxaj3aO30cugbfb4L7BwAAADyUfwDmcbblze7mOAAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"happy": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"sad": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"confused": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFd0lEQVR4nO3dMW5TWxAG4N8PvQaFmsdbABvIAhB7ShqUFpqwJwR9NsACAjRUiAKK+wob8UxyhntzbMuHfF/LdWY01u8QyZpJAAAAgKOw+s2/nyR5nORhkr93XPt7kq9JPiX5csefoT/93dWs/qqA/JPk3x031XKd5OPC1+jvJ/31afb3V+MFJzlcc9nUOlnwvP626a9Ps79WQB7vr5emJTX111dTfzNrtgLycI+NtCypqb++mvqbWbMVkF3/QTTHkpr666upv5k1WwEBIiBQEhAoCAgUBAQKAgIFAYGCgEBBQKAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKLQC8v2gXSyvqb++mvqbWbMVkK97bKRlSU399dXU38yarYB82mMjLUtq6q+vpv5m1nzQePhbkinJo721s+06yecFz+tvm/76NPuzvLpNf33uQ38AAAAAAAAAcM8M/VWTaZqeJTlPcpr12eBd+pjkKsnlarV6e8efYX6Dz2/YO+nTNL1I8nI/7WyXSnKxWq1eLXyd+W1KZeD5tQJykuTp3tq53fvM/CTcfPK9ye9/A+7KlOT5gk9C8/ulZAad36h30s9zuDc3m1pnC543v23Dzm/UO+mne+tiNzXNr6/m0cxv1Dvpu/6Dco4nC541v5uGnJ+tJlAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKAgIFAQECgICBQGBgoBAQUCgICBQEBAoCAgURr2TvmgH1I58WPCs+d005PxGvZN+tbcudlPT/PpqHs38Rr2Tfpn1MrJDmTY15zK/bcPOrxWQL1mvYzyU6yzYL7vZ0HeRw7zJP1ZnvlvwGvP7aej5/QnLq8+yXkq2ZO/SHB+y/m/B65GXL1fMz510AAAAAAAAAFhm6K+aRH/6u7s/+0569Pd/+uvT7K/1bd6THK65bGqdLHhef9v016fZ36h30vXXV1N/M2uOeiddf3019Tez5qh30vXXV1N/M2vaagIFAYGCgEBBQKAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKAgIFAQECgICBQGBgoBAYdQ76frrq6m/mTVHvZOuv76a+ptZc9Q76frrq6m/mTUfNB7+lvV960d7a2fbdZLPC57X3zb99Wn2Z3l1m/763If+AAAAAAAAAOCeGfqrJtM0PUtynuQ067PBu/QxyVWSy9Vq9faOP8P8Bp/fsHfSp2l6keTlftrZLpXkYrVavVr4OvPblMrA82sF5CTJ0721c7v3mflJuPnke5Pf/wbclSnJ8wWfhOb3S8kMOr9R76Sf53Bvbja1zhY8b37bhp3fqHfST/fWxW5qml9fzaOZ36h30nf9B+UcTxY8a343DTk/W02gICBQEBAoCAgUBAQKAgIFAYGCgEBBQKAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKIx6J33RDqgd+bDgWfO7acj5jXon/WpvXeympvn11Tya+Y16J/0y62VkhzJtas5lftuGnV8rIF+yXsd4KNdZsF92s6HvIod5k3+szny34DXm99PQ8/sTllefZb2UbMnepTk+ZP3fgtcjL1+umJ876QAAAAAAAACwTPlVE3e03SHv8EfMrxkQd7S3uEPeZ9j53RoQd7Rv5Q55nyHn1/q6uzvafTXNr6/m0cyvFRB3tPtqml9fzaOZXysg7mj31TS/vppHMz9bTaAgIFAQECgICBQEBAoCAgUBgYKAQEFAoCAgUBAQKAgIFAQECgICBQGBgoBAQUCgICBQEBAotALijnZfTfPrq3k082sFxB3tvprm11fzaObXCog72n01za+v5tHM79aAuKN9gzvkfYad35zl1e5ou0N+F/dhfgAAAMCh/AecHIXJK5h09QAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"angry": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"asleep": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"surprised": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFc0lEQVR4nO3dP25UVxQG8G8SpUFODWQBbMALiNiT3SC30Jg9Iei9ARbAnyYVogjFpJhBycR+h/d8543uNb9fmzHn07E+EyTrngQAAADowuYH//0syeMkj5L8duTZ35J8TfI5yZf7/AHb7fbPJJdJzpM8OV60JMmnJDdJrjebzdt7/hn2N/j+qoI8SfLHkUNN+ZDdQmfbbrcvkrxcJ87hqCRXm83m1cKvs7/9qAy8v6mCnCV5tlqcu73PzJ+E+598b/LjvwGPZZvk+YKfhPb3v5EZdH+/THz48bpZmmde5nTf3OxnXSz4vP0dGnZ/UwV5tGKQKUtmnq+W4jgz7a9tZjf7myrIsf9BNMeSmcf+B+UcTxd81v5uG3J/UwUBoiBQUhAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKEwV5NtJUyyfuegNqCP5uOCz9nfbkPubKsjXFYNMWTLzZrUUx5lpf20zu9nfVEE+rxhkypKZ19k9RnYq2/3Muezv0LD7myrIl+yeYzyVD1nwvuz+hb6rnOab/P3pzHcLvsb+/jX0/h7C49UX2T1KtuTdpTk+Zve/Ba9Hfny5Yn9t+wMAAAAAAACAn8/Qv2oS+eS7v4d9Jz3y/Zd8bSbzTf0271lOFy77WWcLPi/fIfnaTOYb9U66fG0z5Zs5c9Q76fK1zZRv5sxR76TL1zZTvpkzvWoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQGHUO+nytc2Ub+bMUe+ky9c2U76ZM0e9ky5f20z5Zs78deLDf2d33/r31eIc+pDkrwWfl++QfG0m83m8epp8bX6GfAAAAAAAAADwk/GrJtOa82232z+TXCY5z+6s8TF9SnKT5Hqz2by955/R9f7SQT530udZnG+73b5I8nKdOIejklxtNptXC7+u6/2lk3xTBTlL8my1OHd7n/k/abrOt/+b401+/Df0sWyTPF/wN0nX+0tH+dxJX2fmZU5XjuxnXSz4fO/76yafO+nrzDxfLcVxZva+v27yuZO+zsxj/4N8jqcLPtv7/rrJ51UTKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBArupK8zc+kbUMfwccFne99fN/ncSV9n5s1qKY4zs/f9dZPPnfR1Zl5n95jbqWz3M+fqfX/d5JsqyJfsnmM8lQ9Z9n5r1/n2Lxxe5TQl+f706LsFX9P1/tJRPo9XTzvW49UX2T3qtuTdqjk+Zve/Va89Xn0v7qQDAAAAAAAAwGJD/6qJO+T21+Bh30l3h/yA/bV5WHfS3SG/k/21eVB30t0hb5tpfzNnjnon3R3ytpn2N3PmqHfS3SFvm2l/M2d61QQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBwqh30t0hb5tpfzNnjnon3R3ytpn2N3PmqHfS3SFvm2l/M2cOeSfdHfJb7K/Nw7yT7g65/TVwJx0AAAAAAAAAFhv6V03SeT53yMf//g57Jz2d53OH/MCw398h76Sn83zukN9pyO/vqHfSe8/nDnnbzG7yjXonvfd87pC3zewm36h30nvP5w5528xu8nnVBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYHCqHfSe8/nDnnbzG7yjXonvfd87pC3zewm36h30nvP5w5528xu8g15Jz2d53OH/JZhv78er57mDnmbB//9BQAAAE7oHzt4fMP9uDtRAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"silly": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"fabulous": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"meh": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"tshirt": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF1ElEQVR4nO3dMW4UWRAG4OqVSCxyAwfgAMsBLO4ECXIKCdxmN0eQswfYA9jrHDmxxNugx2gtpovu6e6hpvf7UsZTv9rvt0EaXkUAAAAAJXTZH7bWLiLidUS8iIgnC8/+JyK+RMT7rus+HfIG1fNFxOOIOI+Is4h4tFSwnbuIuI2Im4j4esgbVH9+FfINFqS19iYi3i4cau+oiLjsuu7dpC8qni/6b+izFfLscxX9N3y06s+vSr69Bdk19+PQn6+gRcTLsT9pqueL/jfH8xXz7PN3jPxNUv35Vcr328AXvI7jhYvdrFcTXl893/laQRaaWf35lck3VJAX62UZNGVm9Xxnq6VYZmb151cm39Bfsdq6Wfbrum7UT43q+SLi91WDDPtrzIuqP79K+YZ+gwChIJBSEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIDBVk0h1LC7me8Nrq+e5WS7HMzOrPr0y+oYJ8WTHIkCkzq+e7XS3FMjOrP78y+YYK8j76y7SOpe1mjlU9381aQRaaWf35lcm3tyC7G+Yu4zgh769+/Dz2C6rni/6Gw6uV8uxzFRPu563+/CrlG3N59avoL9V6unCw6+h/rX2Yeblx2XxxGpdXl31+1fMBAAAAAAAAAA+01i5aa3+21q7b8q53730hn3wnl6+19maFUPt8a/1ObPnkO418rW/utyMFvA85usnyyXesfPakjyPfPCebz570dWbKN29mmXz2pE8g3zynmM+tJpBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgk7EkfT755TjKfPenrzJRv3swy+exJH0e+ebaW7/vVj8e43W7O1ZTyyfdL8t2HvGit/dFau1oh2NXuvedebiyffL8kHwAAAAAAAAD8//xsJdbjiDiPiLOIeLTw7LuIuI2Im4j4esgb7D4m8Dr6/XJPlosWEf1Hrr9ExPuu6z4d8gbyzcsXBc5fVpAnEfFs4VBDrmLi/wFo/QfM3q4T5+GoiLjsuu7dpC+S7/uoOCBfFDl/QwV5HBHPV4uz398x8jfJ7iffxzjequAWES/H/iSU78eRMSFfFDp/Q/8f5HzdLLNnltmjPUC+h6bmK3P+hgpytmKQIVNmltmjvcBrl7KlfGXO31BBlv4H0RhTZi79D8oxnk54rXw/mpKvzPlzqwkkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCiaGC3B01xfSZZfZoD5DvR1PylTl/QwW5XTHIkCkzy+zRXuC1S9lSvjLnb6ggNysGGTJlZvU92vI9NDVfmfM3VJCv0V/HeCxXMeF+3t0NfZdxnG/y/dWZn8d+gXwPTM4Xhc7fFi6vfhX9pWRT7l0a4zr6vxZ8mHk5tHwnfHk1AAAAAAAAAPBfW/ioSdk93/LZk74Ue9IPt8l8UeT82ZM+zqb2kFfPF4XOnz3p42xtD3n1fGXOnz3p68yUb97MMufPnvTxtrSHvHq+MufPrSaQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJOxJH29Le8ir5ytz/uxJX2emfPNmljl/9qSPs7U95NXzlTl/9qT/3Ob2kFfPF4XO3xYury6751s+e9IBAAAAAAAAYFu28FGTsnu+5bMnfSn2pB9uk/miyPmzJ32cTe0hr54vCp0/e9LH2doe8ur5ypw/e9LXmSnfvJllzp896eNtaQ959Xxlzp9bTSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBI2JM+3pb2kFfPV+b82ZO+zkz55s0sc/7sSR9na3vIq+crc/7sSf+5ze0hr54vCp2/LVxeXXbPt3z2pAMAAAAL+RdTjm3JtMq/IQAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"rollerskate": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"duck": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFW0lEQVR4nO3dMXIcVRQF0DdQJC4R27AAFoAXQLEnO6GcQmL2REFuFsACZJwQuRzgYAhGYKZm/tP/+t1Tr0fnpG7p36ruK1tlqW8EAAAAUMLunj+/iYinEfEkIr5Y+OyPEfEhIt5FxPuHfIL9fv9dRLyMiOcR8Wy5aBER8WdEvImI17vd7teHfILq+aL4/Y0C+bKCPIuIrxcO1XIbhxvebb/f/xARP64T5/ioiHi12+1+Gvqg4vmi+P2NIvlaBbmJiG9Wi3PeH9H5lebuK/Mvcf/fgEvZR8T3vV+pq+eL4vc3CuX7rHHx03WzTJ/5Mi738MXdWS8Grq+er/r9LZOvVZAnKwZpGTnz+Wopljmzer7q97dMvlZBlv6GqMfImUt/w9vjq4Frq+erfn/L5GsVBAgFgZSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkCiVZCPF00xfuboO5aW8Hbg2ur5qt/fMvlaBfmwYpCWkTPfrJZimTOr56t+f8vkaxXk3YpBWkbOfB2Hl6Vdyv7uzF7V81W/v2XytQryPg6vY7yU2xh4f+vdGwRfxWUewn9f7flb7wdUzxfF728UyncNL69+EYeXpo28F6rH2zj8s+XnyZdXl80Xxe9v1M8HAAAAAAAAAI9M+qMm1Xe+5bOTPmFuJ736zrd8n44KO+mzxnbSq+98y3d6ZNhJnzW0k15951u+Y3bS5w3tpFff+ZZv7swyO+QLXLuUoZ306jvf8p2ykz7HTjqMUhBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJFoFqb7zLd8pO+lzhnbSq+98yzd3Zpkd8gWuXcrQTnr1nW/5jtlJn9e/k15951u+I3bS5z1sJ736zrd8dtIn2EkHAAAAAAAAgGH3DU2W/q/+6jvk8m0/X1aQEjvVLdV3yOX7dFRsOF+rIGV2qs+pvkMu3+mRsdF8rd8HKbNT3VB9h1y+Y5vN1ypImZ3qhuo75PLNnVkmX6ul364YJPN7z0X7/f6Sv633n91u1/VVTb7ztpjPW00goSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSLQKUmanuqH6Drl8pzaZr1WQMjvVDdV3yOWbO7NMvlZByuxUN1TfIZfv2GbztQpSZqf6nOo75PId2XS+a3h5ddkdcvmuOx8AAAAAAAAAPD7X8KMmdr6vNF8UeP7spHccFRve+W5+UPF8UeT5s5PeZ7M732cvLp4vCj1/dtL7bHbnu6F6vjLPn530dc6Ub+7MMs9fqyBLf0PUY+TMpb+h7DHy+wjynRrJV+b581YTSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBJ20vttcue7oXq+Ms+fnfR1zpRv7swyz5+d9D6b3fluqJ6vzPNnJ/1+m975Pqd6vij0/F3Dy6vL7mjLN71DXvr5AwAAAAAAAIDHZ9M/ahLyyfdw172THvL9n3xzmvlaP817E5cLF3dn3QxcL98x+eY08211J12+uTPl6zxzqzvp8s2dKV/nmVvdSZdv7kz5Os/0VhNIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEElvdSZdv7kz5Os/c6k66fHNnytd55lZ30uWbO1O+zjM/b1z8dxz2rb9cLc6x24j4a+B6+Y7JN6eZz8ur2+Sb8xjyAQAAAJfyD92s8bBtlgWFAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"house": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"tortoise": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"butterfly": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"stickfigure": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"ghost": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"sword": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE40lEQVR4nO3dMY4UVxQF0NeWnCBysBfgDbAAy3uCBJHaCd6TZedswAsAkyMSgnYwY1mjoS5V86ta7/eckzLwrrq4HiON6lYBAAAALZy+8etPq+pZVT2pqu93vv2lqj5X1ceq+vTAP6N1vvP5/HNVvaqqF1X1fL9oVVX1T1W9q6q3p9Ppzwf+Ga0/v2qQLxXkeVX9uHOoJe/r5oFv0Trf+Xx+XVW/HhPn7qmqenM6nX7b+Ptaf37VJN9SQZ5W1U+Hxfm6v2v9f2la57v9zvFHffs79F7OVfXLhu8krT+/apTvu4UvfnZsluGb3fO9qsuVo25vvdzw9d0/vzb5lgry5MAgS7bc7J7vxWEp9rnZ/fNrk2+pIHv/g2iNLTe759v7H+Rr/LDha7t/fm3yLRUEKAWBSEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBYKsiXi6bYfrN7vq3vgNrDhw1f2/3za5NvqSCfDwyyZMvN7vneHZZin5vdP782+ZYK8vHAIEu23Oye723dvMztUs63N9fq/vm1ybdUkE918zrGS3lf297f2jrf7RsO39RlSvLfq0f/2vB7Wn9+1Sifl1cv2+vl1S/r5qVuW95btcaHuvnfqt+9vPpB9sgHAAAAAAAAAI+MHzVZZid9zFU8Xzvp69hJHzPt87WTvp6d9DFTPl876cfctJM+drNNPjvpx9y0kz52s00+O+nH3LSTPnazTT5vNYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCOykH3PTTvrYzTb57KQfc9NO+tjNNvnspB9z00762M02+eykr2Mnfcy0z9fLq5fZSR9z9c8XAAAAAAAAAB4fP2qyzE76mKt4vnbS17GTPmba52snfT076WOmfL520o+5aSd97GabfHbSj7lpJ33sZpt8dtKPuWknfexmm3zeagKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgENhJP+amnfSxm23y2Uk/5qad9LGbbfLZST/mpp30sZtt8tlJX8dO+phpn6+XVy+zkz7m6p8vAAAAAAAAADw+U/+oSfcdcvnm33Gfdie9+w65fP+fqol33KfcSe++Qy7f/ZM16Y77rDvp3XfI5btr2h33WXfSu++Qyzd2s83fv1l30rvvkMt335Q77t5qAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQzLqT3n2HXL77ptxxn3UnvfsOuXxjN9v8/Zt1J737Drl8d0274z7lTnr3HXL57ph6x/0aXl7ddodcvqvfcQcAAAAAAACAR2bqHzWp5vnskM//fKfdSa/m+eyQ3zHt851yJ72a57ND/lVTPt9Zd9K757NDPnazTb5Zd9K757NDPnazTb5Zd9K757NDPnazTT5vNYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCGbdSe+ezw752M02+WbdSe+ezw752M02+WbdSe+ezw752M02+abcSa/m+eyQ3zPt8/Xy6mVXv+NezT+/6p8PAAAAuJR/ATEXlVHvyECcAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"giraffe": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE+UlEQVR4nO3dPY4cVRQF4NtIJBY5PwtgA14AYk92gpxCYvaEIPcGWICNc+TEQRP0IGs09U6/mqqy3+v5vtRj36PSnBEW7TpVAAAAwBBO6RfP5/NPVfWyqp5X1Xc73/6nqt5U1evT6fTnY/6A0fNV1TdV9W1VPauqr/cKdudjVX2oqvdV9e8j/wz5ruRrFuR8Pv9SVb/uHGrxVFW9Op1Ov636TYPnq0thfzggz5K3dSn0GvJ90sy3WJC7n8x/tH79AOeq+rn3J/Xo+eryk+/HA/Ms+bv6f1LL99Bivq8aX/yyPt83X93derHi60fP9+1RQXa6KV/nzVZBnh8YpGXNzdHzPTssxT435eu82SrI3n/h7fH9iq8dPd/ef6Hc+6Z8nTdbBQFKQSBSEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCFoFWfsOoz28W/G1o+f7eFiKfW7K13mzVZA3BwZpWXNz9HwfDkuxz035Om+2CvK6Li9L+1zOdzd7jZ7v/VFBdropX+fNxYLcvUHwVX2eb8L/X+35V+9vGD1fXd7Q9/agPEve1rr338p3XzNfz8urX9TlpWlr3gvV411d/rPl940vrx42Xw3w8uUr5NuWDwAAAAAAAACemGtDmEP/r3476Tf/UY4vni8VZIid6hY76fdMu0MeDJGvVZBhdqqX2ElfNOUOecMw+Vr/HmSYneoGO+nbbsrXebNVkGF2qhvspG+7KV/nzVZBhtmpbrCTvu2mfJ03vdUEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBoFWSYneoGO+nbbsrXebNVkGF2qhvspG+7KV/nzVZBhtmpbrCTvu2mfJ03WwUZZqd6iZ30B6bdIW8YJt8tvLzaTvrEL4e+YvR8AAAAAAAAAPDE3MJHTeyk3+5HOb54PjvpHafKTvpW0+azk97HTvp2U+azk97HTvp2U+azk37MzdGfn3ydN+2k97OTvs2U+bzVBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgsJPez076NlPms5N+zM3Rn598nTftpPexk77dlPnspF9nJ327afPdwsur7aRP/HLoK0bPBwAAAAAAAABPzC181GTYnXT55t+Zt5PecaoesZMu36dTNfHOvJ30Pqt20uV7eLIm3Zm3k95n7U66fPdNuzNvJ/2Ym/JtuznM95+d9H5r/r2JfA9NuTPvrSYQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGd9H5rdtLle2jKnXk76cfclG/bzWG+/+yk91m7ky7ffdPuzNtJv271Trp890y9M38LL68ediddvpvfmQcAAAAAAACAJ+YWPmpi59vzeww76TuZeue7xfO7x076RtPufC/x/BbZSd9g2p3vBs+v86ad9GNuen7bbg7z/Oyk95ty57vB8+u86a0mECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBnfR+U+58N3h+nTftpB9z0/PbdnOY52cnvc+0O98Nnl/nTTvp1029873E83vATvoj3PzOt+dnJx0AAACm8R/nWLbllDXkpAAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"skull": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"umbrella": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"snake": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFE0lEQVR4nO3dMY5bVRQG4GMQTTTUARbAAsgCIvaUNCgtNGFPCPqwABYwIQ1VlCIpTGHDYOx75r6571nnvfm+djxzfl35t8aSfU8EAAAAUMIu++F+v38eES8j4llEfDXz7D8j4k1EvN7tdr8+5A9UzxcRNxHxNCKeRMQXcwU7+hQRHyLiXUS8f+DfkO+efM2C7Pf7HyLix5lDXRwVEa92u91Pk36peL44FPabBfJcchuHQk8h351mvosFOb4y/9L6+QL2EfF97yt19XxxeOX7dsE8l/wR/a/U8p27mO+zxoNfxvWefHGc9WLC46vne7pUkJlmytc5s1WQZwsGaZkys3q+J4ulmGemfJ0zWwWZ+w1vj68nPLZ6vrnfUM49U77Oma2CAKEgkFIQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEi0CjL1DqM5vJ3w2Or5Pi2WYp6Z8nXObBXkzYJBWqbMrJ7vw2Ip5pkpX+fMVkFex+GytGvZH2f2qp7v3VJBZpopX+fMiwU53iD4Kq7zJPznas/fen+her443NB3u1CeS25j2v238p1q5uu5vPpFHC5Nm3IvVI+3cfi35efBy6vL5osCly/fQ76xfAAAAAAAAADwyNiT3rb5PenVz69CPnvSO0bFBvekVz+/KvnsSe+zqT3p1c+vUj570vtsbU969fMrk8+e9GVmltnz3VD9/Mrka/2Ldc1v6/1rt9t1vWpUzxcR3y0apO33ngdVP79K+dxqAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkDCnvR+W9qTXv38yuSzJ32ZmWX2fDdUP78y+exJ77O1PenVz69MPnvS77e5PenVz69SPnvS2za/J736+VXPBwAAAAAAAACPz30rsdbwUYmye77D+a3+/LKC2PN9HBX2pI9Y9fm1CmLP9/9Ghj3pI1Z7fq3vg9jzfcqe9DGrPb9WQez5Hpvp/MZmljm/VkHmfkPUY8rMud9Q9pjyfQTnd26V5+dWE0goCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSrYLY833OnvQxqzy/VkHs+R6b6fzGZpY5v1ZB7Pk+ZU/6mNWeX6sg9nzfsSd9zKrPbwuXV1feo+38Nnx+AAAAAAAAAPD4bOGjJmX3fMtnT/pcNrfnW767UWFP+iw2s+dbvvORYU/6sC3t+ZbvlD3pM9jSnm/5xmaWef7Zk95vyvcl5DtnTzpsjYJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIGFPer8pe77lO2dP+qAt7fmWb2xmmeefPel9pu75lu+UPemDNrXnW74T9qQ/0Ob3fMtnTzoAAAAAAAAAbMuqP2oS8sn3cNvekx7y/Zd8Y5r5Wp/mvYnrhYvjrJsJj5fvlHxjmvnWuiddvrGZ8nXOXOuedPnGZsrXOXOte9LlG5spX+dMt5pAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFjrnnT5xmbK1zlzrXvS5RubKV/nzLXuSZdvbKZ8nTM/bzz4Yxz2W3+5WJxTtxHx14THy3dKvjHNfC6vbpNvzGPIBwAAAFzL3/Yj4OZvgj/VAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"rabbit": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE50lEQVR4nO3dTW4UVxQF4FuRMkHMIVlAFgALiLInmERMkwnZU5TMYQFZAD9zxIRBZ2AH3O5+J1V+Va3Xpe8bGtv36prTsiW7ThUAAAAwhCn94+Fw+LmqXlbV86p6uvLsD1X1pqpeT9P01wM/x+OqelJVj6rq+7UWu/Wlqj5X1ceq+vSQT+B+fferAfZrBuRwOPxaVb+tvNTZUVX1apqm3xd+3NOq+nGDfc55Vzf/IWdzvyOL71eD7Hc2ILevfH+2/n0Dh6r6ZcEr4eOq+mnDfc75p2a+ErrfWbPvVwPt913jnV/W5b64dTvrxYL3f7LVIivNdL++mcPs1wrI8w0XaVky89FmW6wz0/36Zg6zXysga/9AOccPC9537R/Y1p7pfn0zh9mvFRCgBAQiAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgaAVkKXPMFrD+wXv+2WzLdaZ6X59M4fZrxWQNxsu0rJk5ufNtlhnpvv1zRxmv1ZAXtfNw8gu5XA7c66PWy2y0kz365s5zH5nA3L7hL5XdZkv8n+Pzvx7wcd8qpvHRV7Ku1rwfFn3O7HofjXQfnMeXv2ibh5KtuS5S3O8r5tvC/7Y68OX3e/6H14NAAAAAAAAANylJ71NT3qfXfyqiZ70efSk99GT3mlXPd/ud5ae9A576/l2v76Zw+ynJ32bme7XN3OY/fSkbzPT/fpmDrOfp5pAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAR60reZ6X59M4fZT0/6NjPdr2/mMPvpSd9mpvv1zRxmPz3p8+hJ76Mn/QF23/Ptftf/8GoAAAAAAAAA4K6r7km33773qwF+1eRqe9Lt921U7XC/0pN+PLIW9Hzb73Rk7Wi/0pN+YmnPt/2O7W0/PemdM+3XN3P0/YbpSW99i3XJv4b7apqmWa9q9jtvL/tV1bNNF2l7e/8NnmoCgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBBca0+6/U7taT896Z0z7dc3c/T99KTfs7Tn237H9rafnvQ7Fvd82+/I7vYrPelVtULPt/32vV8N8PBqAAAAAAAAAOAuPeltu+j5TtxPT/oarrrnu8X9juhJ73S1Pd/nuN9ZetI7XG3Pd4P7zZypJ32bmcP0fDe438yZrYCs/QPbHEv+HmH0/db+gXLtme43c6anmkAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBHrS57vKnu8G95s5U0/6NjOH6flucL+ZM/Wkz3O1Pd8N7jdzpp70/3fVPd/nuN8JPekPsPueb/fTkw4AAAAAAAAAy+hJb7NfHz3pK9llT7r9vo0qPenddtWTbr/TkaUnvcveetLtd0xP+gr21JNuv76Zw/Skt77FuuRfm301TdOsVzX7nbeX/arq2aaLtL29/wZPNYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCPSkz2e/PnrSO+2pJ91+fTP1pN+zt550+x3Tk95hdz3p9juiJ/2Bdt+Tbj896QAAAMBK/gVsdTwSu+HRwQAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"cow": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"quarternote": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE8ElEQVR4nO3dQY4VZRQF4PtMnBDmoAtwAyzAuCeYEKY6wT0ZnbMBFwAyJ0wYPAfdxnTaOl3V/1/P+4rvm1pwT97LAUk6daoAAACAFk4P/PenVfWsqp5U1beTb3+pqs9V9bGqPj3y92id73w+/1hVr6rqRVU9nxetqqr+qqp3VfX2dDr9/sjfo/XnVw3ypYI8r6rvJ4da8r5uvvAtWuc7n8+vq+rnfeLcPVVVb06n0y8bf13rz6+a5FsqyNOq+mG3OP/tz1r/J03rfLd/c/xWD/8NPcu5qn7a8DdJ68+vGuX7ZuHhZ/tmGb7ZPd+rulw56vbWyw3Pd//82uRbKsiTHYMs2XKze74Xu6WYc7P759cm31JBZv+DaI0tN7vnm/0P8jW+2/Bs98+vTb6lggClIBApCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBEsF+XLRFNtvds+39R1QM3zY8Gz3z69NvqWCfN4xyJItN7vne7dbijk3u39+bfItFeTjjkGWbLnZPd/bunmZ26Wcb2+u1f3za5NvqSCf6uZ1jJfyvra9v7V1vts3HL6py5Tkn1eP/rHh17T+/KpRPi+vXjbr5dUv6+alblveW7XGh7r536pfvbz6UWbkAwAAAAAAAICvjB81WWYnfcwhvl876evYSR9ztd+vnfT17KSPucrv1076PjftpI/dbJPPTvo+N+2kj91sk89O+j437aSP3WyTz1tNIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCO+n73LSTPnazTT476fvctJM+drNNPjvp+9y0kz52s00+O+nr2Ekfc7Xfr5dXL7OTPubw3y8AAAAAAAAAfH38qMkyO+ljDvH92klfx076mKv9fu2kr2cnfcxVfr920ve5aSd97GabfHbS97lpJ33sZpt8dtL3uWknfexmm3zeagKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgENhJ3+emnfSxm23y2Unf56ad9LGbbfLZSd/npp30sZtt8tlJX8dO+pir/X69vHqZnfQxh/9+AQAAAAAAAODrE3/UpPvOt3x20geM7aR33/mW799TZSd91Lad9O473/LdP1l20kdt2knvvvMt31120sdt2knvvvMt39jNNjvkE56dZdNOevedb/nus5M+xk46bKUgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgESwXpvvMt33120sds2knvvvMt39jNNjvkE56dZdNOevedb/nuspM+bv1Oevedb/nusJM+7nE76d13vuWzkz7ATjoAAAAAAAAAbGYnfdnh81X/H+X43/PZSV9xqg6Yr5rskAct8tlJX+dQ+arRDvmCNvnspK9ztHxtdsgnPDuLnfRBR8rXZod8wrOz2EkfdKR8bXbIJzw7i5102EpBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAI7KSvd6R8bXbIJzw7i530QUfK12aHfMKzs9hJH3C0fG12yCc8O4ud9Ec6XL5qtEO+oE0+O+nLDp+vGrwc+gHd8wEAAACX8jdzZLbl0C/0iwAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"eigthnote": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFM0lEQVR4nO3dQY4VVRgF4P+ZOCHMQRfgBliAcU8wMUx1gnsyOmcDLgBkTpgweA66JXa6799V/W61J5fvm1pwT27lgCSdOlUAAABAhNM9//1pVT2rqidV9e3ksz9X1aeq+lBVHx/4e0TnO5/PP1bVq6p6UVXP50Wrqqq/q+ptVb05nU5/PPD3iL6/CsjXFeR5VX0/OdTIu7p64XtE5zufzz9X1S/HxLl5VFW9Pp1Ov+78ddH3VyH5RgV5WlU/HBbnbn/V9j9povNd/83xe93/N/Qs56r6acffJNH3V0H5vhk8/OzYLBefmZ7vVT1eOer6rJc7nk+/v5h8o4I8OTDIyJ4z0/O9OCzFnDPT7y8m36ggs/9BtMWeM9Pzzf4H+Rbf7Xg2/f5i8o0KApSCQEtBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaAxKsjnR02x/8z0fHu/ATXD+x3Ppt9fTL5RQT4dGGRkz5np+d4elmLOmen3F5NvVJAPBwYZ2XNmer43dfUxt8dyvj5zq/T7i8k3KsjHuvoc42N5V/u+3xqd7/oLh6/rcUry76dH/9zxa6Lvr4Ly+Xj12KyPV7+sq4+67flu1Rbv6+p/q37z8eoHmZEPAAAAAAAAAL4yftRkbPmd9PR8FfB+7aRvs9xOenq+Cnm/dtK3W2YnPT1fBb1fO+nHnJm+k56eL+b92kk/5sz0nfT0fDHv1076MWem76Sn54t5v75qAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkDDTvoxZ6bvpKfni3m/dtKPOTN9Jz09X8z7tZN+zJnpO+np+WLer530bZbaSU/PV0Hv18erx5bfSU/PV+HvFwAAAAAAAAC+Pn7UZGz5nfRyf/fen530bZbbSS/39+Woau7PTvp2y+ykl/u7dWQN7s9O+jFn2iG/7MyY+7OTfsyZdsgvOzPm/uykH3OmHfLLzoy5P181gYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaBhJ/2YM+2QX3ZmzP3ZST/mTDvkl50Zc3920o850w75ZWfG3J+d9G2W2kkv9/df7f35ePXY8jvp5f4uvT8AAAAAAAAA+Mq0P2qSsFPdkW/tnfQKyDcsSMpO9fAXyfflqFpwJ71C8t1ZkKSd6jsflu/WkbXQTnoF5Rv9uHvMTvWAfDettpMek29UkJid6gnPzrJSvvSd9Jh8o4LE7FQPyHfbSjvpMfl81QQaCgINBYGGgkBDQaChINBQEGgoCDQUBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBxqggMTvVA/LdttJOeky+UUFidqonPDvLSvnSd9Jj8o0KErNTPSDfTavtpMfku7MgSTvVd5HvhuV20iso35aPV8fuVMu39k565ecDAAAAAAAAgK+MnfSx5fNV/o9y/O/57KRvOKoWzFchO+SNiHx20rdZKl8F7ZAPxOSzk77NavlidsgnPDuLnfQLrZQvZod8wrOz2Em/0Er5YnbIJzw7i5102EtBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaChINCwk77dSvlidsgnPDuLnfQLrZQvZod8wrOz2Em/wGr5YnbIJzw7i530B1ouXwXtkA/E5LOTPrZ8vgr4OPQ90vMBAAAAj+Uf73PYeRwCFc4AAAAASUVORK5CYII="
|
||||
},
|
||||
"pitchfork": {
|
||||
"icon": "data:image/png;base64,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"
|
||||
},
|
||||
"target": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFeElEQVR4nO3dMY5bVRgF4N9INFH6BBbAAsgCEHtKGpQWmrAnBH1YAAtISB+lSWGKGYiMff/xm/dsnTvzfW08uUfP72QykuedKgAAACDC7o4/f1pVz6rqSVV9vfHZn6vqU1V9qKqP9/w7ovPt9/sfqupVVb2oqufbRauqqr+r6m1Vvdntdr/f8++Ivn4VkK8ryPOq+nbjUCPv6uYNXyI6336//6mqfr5MnMOjqur1brf7ZeHXRV+/Csk3KsjTqvruYnFO+6vO/5cmOt/td47f6u7v0FvZV9WPC76TRF+/Csr31eDFzy6bZfWZ6fle1fXKUbdnvVzw+vTrF5NvVJAnFwwysuTM9HwvLpZimzPTr19MvlFBtv6B6BxLzkzPt/UP5Of4ZsFr069fTL5RQYBSEGgpCDQUBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0RgX5fNUUy89Mz7f0GVBbeL/gtenXLybfqCCfLhhkZMmZ6fneXizFNmemX7+YfKOCfLhgkJElZ6bne1M3D3O7lv3tmedKv34x+UYF+Vg3j2O8lne17Pmt0flun3D4uq5Tkn8fPfrHgq+Jvn4VlM/Dq8e2enj1y7p5qNuS51ad433d/LfqVw+vvpct8gEAAAAAAADAIzP1R03Sd8jlm3/Hfdqd9PQdcvm+HFUT77hPuZOevkMu3/GRNemO+6w76ek75PIdmnbHfdad9PQdcvnWnRlz/826k56+Qy7fsSl33D3VBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYHGrDvp6Tvk8h2bcsd91p309B1y+dadGXP/zbqTnr5DLt+haXfcp9xJT98hl+/A1DvuD+Hh1bE75PI9+B13AAAAAAAAAHhk2o+apO9op+er8I9KpF+/hHzDgqTvaKfnq5Cd75H065eS72RB0ne00/NV0M73KenXLynf6OPu6Tva6flidr4H0q9fTL5RQdJ3tNPzxex8D6Rfv5h8o/9iXfO3zf6z2+3O+lcjPV9VfX/RIGN/nvOi9OuXlM9TTaChINBQEGgoCDQUBBoKAg0FgYaCQENBoKEg0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBojAqSvqOdni9m53sg/frF5BsVJH1HOz1fzM73QPr1i8k3Kkj6jnZ6vpid74H06xeT72RB0ne00/NV0M73KenXLynfOQ+vjt3RTs9Xczy8Ovb6pecDAAAAAAAAgMfnrkmsGT4qYef7geargPuvK4id79ujauKd7+EXheerkPtvVBA73/87sibd+T754vB8FXT/jX4fxM73oWl3vgfS88Xcf6OC2Pled6Z8686Muf9GBdn6B6JzLDlz6x8oz7Hk9xHkO7YkX8z956km0FAQaCgINBQEGgoCDQWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaChINBQEGgoCDRGBbHzfWzKne+B9Hwx99+oIHa+150p37ozY+6/UUHsfB+adud7ID1fzP03Koid7y+m3vk+JT1fBd1/D+Hh1bE72vI97J15AAAAAAAAAHh8pv6oSYXns0M+//s77U56heezQ35g2vd3yp30Cs9nh/ykKd/fWXfS0/PZIV93Zky+WXfS0/PZIV93Zky+WXfS0/PZIV93Zkw+TzWBhoJAQ0GgoSDQUBBoKAg0FAQaCgINBYGGgkBDQaChINBQEGgoCDQUBBoKAg0FgYaCQENBoDHrTnp6Pjvk686MyTfrTnp6Pjvk686MyTfrTnp6Pjvk686MyTflTnqF57NDfmTa99fDq8ce/I57hV+/ys8HAAAAXMs/4tr5dC58svsAAAAASUVORK5CYII="
|
||||
},
|
||||
"triangle": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFX0lEQVR4nO3dsW5URxQG4LNBNJapTXiAvAAPYOWdoEG0SUPeJumjpOcF8gA2bqiQCywxKXYBrfAcZjz3LrP297Xc3fNrpN+LpfWcCAAAAGAKm+/8+2lEnEXESUQ8Xnj2TURcR8RVRHy443vIJ99dNeXLCvI0Ip4tHKrmIiLedb5Gvq/kG1PN91PlBadxuHCxm3Xa8bx8++QbU81XK8jZelmqembKNzZTvsaZtYKcrBikpmemfGMz5WucWSvI0r8QteiZKd/YTPkaZ9YKAoSCQEpBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSBRK8jNQVP0z5RvbKZ8jTNrBbleMUhNz0z5xmbK1zizVpCrFYPU9MyUb2ymfI0zH1Ue/hgRJSKerBZn30VEvO94Xr598o2p5nN5dZ18Yx5CPgAAAAAAAAB4YHzVpG44XynlPCJeRsTz2K41XtK7iHgbEW82m80/d3yPqc8vJshnT3qb7nyllFcR8ds6cfZHRcTrzWbze+frpj6/mCRfrSCnEfHLanFu91+0/6SZOt/uk+Pv+P4n9FJKRPza8Uky9fnFRPnsSV9n5ss4XDliN+tFx/Ozn980+exJX2fm89VSLDNz9vObJp896evMXPoX8hY/dzw7+/lNk8+tJpBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgk7ElfZ2bvHVBLuOx4dvbzmyafPenrzHy7WoplZs5+ftPksyd9nZlvYnuZ26GU3cxWs5/fNPlqBfkQ2+sYD+Ui+u5vnTrf7obD13GYkny+evTfjtdMfX4xUT6XV9ctdXn1i9he6tZzb1WLy9j+t+oPl1ffiT3pAAAAAAAAANDtqL9qYg+58xtwv/ek20O+x/mNuV970u0hv5XzG3Ov9qTbQz420/k1zjzWPen2kI/NdH6NM491T7o95GMznV/jTLeaQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJA41j3p9pCPzXR+jTOPdU+6PeRjM51f48xj3ZNuD/nYTOfXOPMo96TbQ/4N5zfmfu5Jt4fc+Q2wJx0AAAAAAAAAllVKOS+l/FVKuSzLu9y997l88h1dvlLKqxVC3eZT2e7slk++48hXts39dKCAn0M2N1k++Q6Vr/Z199n3aMu3T74x1Xy1gsy+R1u+sZnyNc68taWllEP+tdkXm82m6aeGfLeTb8xt+dxqAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkCiVpDZ92jL9y35xtyar1aQ2fdoyzc2U77GmbWCzL5HW7598o3pzffl6sdD3G43cjWlfPL9kHyfQ56XUv4spVysEOxi996jlxvLJ98PyQcAAAAAAAAAD8/3VmKdRsRZRJxExOOFZ99ExHVEXEXEhzu+h3zy3VVTvqwgTyPi2cKhai6i/28A5PtKvjHVfLWvu5/G4cLFbtZpx/Py7ZNvTDVfrSBn62Wp6pkp39hM+Rpn1gpysmKQmp6Z8o3NlK9xZq0gS/9C1KJnpnxjM+VrnOlWE0goCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQStYLcHDRF/0z5xmbK1zizVpDrFYPU9MyUb2ymfI0zawW5WjFITc9M+cZmytc481Hl4Y+xXa7+ZLU4+y4i4n3H8/Ltk29MNZ/Lq+vkG/MQ8gEAAACH8j9qsKYdhQgxPgAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"lefttriangle": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFGklEQVR4nO3dPY4UVxQG0NuWnCBysBfgDbCAkfcECSK1E7wbO7fsnA14ATOQIxIknoPuAY+m6rpq6lVzX3NOOtV9P1Xpmx+p590IAAAAoIRD9sXW2lVEvIiIZxHxtPPstxHxJiJeHw6Hvx74Ho8j4klEPIqI73sFO/kYER8i4l1EvH/ge8g3eL7ZgrTWXkbEL51DTY6KiFeHw+HXla97GhE/7pBnynUcC72GfF8Mm2+yIKefHH/OfX0HLSJ+XvGT5HFE/LRjnin/xPLvhPLdN2S+72YufhHnK0ecZj1fcf2TvYJ0minftpll8s0V5NmOQeasmflotxR9Zsq3bWaZfHMF6f0H+RI/rLi29x9svWfKt21mmXxzBQFCQSClIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQmCvI2jOMerhZce3H3VL0mSnftpll8s0V5M2OQeasmflhtxR9Zsq3bWaZfHMFeR3Hw9zOpZ1mLvVuryCdZsq3bWaZfJMFOZ1w+CrOU5Lbo0f/XvGa93E8LvJcrmPd+bLy3TVsviWHVz+P46Fua86tWuImjr9W/ebw6geRb5se+QAAAAAAAADgGzP0nvTq+aL+RyXku9Q96dXzRZE93wn5vrisPenV80WhPd8z5LvvovakV89XZs93h2t7GTLfqHvSq+crs+e7w7W9DJlv1D3p1fOV2fPd4dpehsznVBNIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEqPuSa+er8ye7w7X9jJkvlH3pFfPV2bPd4drexky36h70qvnK7Pnu8O1vQyZb8g96dXzRaE93zPku+sy96RXzxcFDl/+H/LZkw4AAAAAAAAAKwy9Jz2KfxTB/Rv/oybD7kmPInu057h/d9iTvtFF7SF3/ybZk77Bpe0hd/+2zSyTb9Q96WX2aM9w/7bNLJNv1D3pZfZoz3D/ts0sk8+pJpBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkRt2TXmaP9gz3b9vMMvlG3ZNeZo/2DPdv28wy+Ubdk15mj/YM92/bzDL5htyTHoX2aE9x/+6xJ/0BLn4Pufs3/uHVAAAAAAAAAMB/2ZM+7+I/KuH52pPey7B7vud4vnfYk97BkHu+p3i+k+xJ32jIPd8zPN+FM+1J32dm9Xye78KZ9qTvM7N6Ps934UynmkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQsCd9n5nV83m+C2fak77PzOr5PN+FM+1J32dm9Xye78KZ9qQvM+ye7yme7z32pD/At3J4tedrTzoAAAAAAAAA9NBau2qt/dFau2n93Zze+0o++YbL11p7uUOoKZ/acWe3fPKNka8dm/vpTAFvQy5usnzynSvfqHvS5btLvm1m8426J12+bTPlWzhzsqWttXP+t9lnh8Nh0XcN+abJt81UPqeaQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJAYdU+6fPfJt81kvlH3pMu3baZ8C2eOuiddvrvk22Ztvs9HP57jdLstR1PKJ99XyXcb8qq19ntr7XqHYNen9956uLF88n2VfAAAAMAZ/QsAIPjNRI6mtwAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"chessboard": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE7klEQVR4nO3dMY5TZxQF4OtIaRA9JAvIBlhAlD1BE9EmDdlTlPRsIAuA0CMaCqcYRyNj/2f85trW+z3f1zJwnw46A0jmnSoAAABgFTYP/PjzqnpRVc+q6vsz3/5aVV+q6lNVfX7ML7Ddbn+uqjdV9aqqXp7v0aqq6t+qel9V7zabzV+P/DXkN3l+qSAvq+rHMz/UyIe6C/Rk2+3216r67TKPs3+qqt5uNpvfF/48+e1O1cT5jQryvKp+utjjHPdPnfidcPed7896+E/Ac9lW1S8LvhPK75uTNWl+3w2++MVln6V9801d7ze3drdeL/h6+e2bNr9RQZ5d8EFGltx8dbGnOM9N+fVuria/UUHO/Q+iUyy5ee5/UJ7ihwVfK79DU+Y3KghQCgKRgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQDAqyNerPsXym4veAXUmHxd8rfwOTZnfqCBfLvggI0tuvr/YU5znpvx6N1eT36ggny74ICNLbr6ru5eRXct2d/NU8ts3bX6jgnyuu9cxXsuHWvB+2d0b+t7WdX6T/3915t8Lfo787k2d3y28vPp13b2UbMl7l07xse7+WvDHzC9fTuTXyw8AAAAAAAAAnp74URM72nbIG24iv2FB7GjvsUPeM21+RwtiR/soO+Q9U+Y3+ri7He3eTfn1bq4mv1FB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryc9bTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEglFB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryW9UEDvavZvy691cTX5HC2JH+4Ad8p5p8zvl5dV2tO2QP8ZTyA8AAAAAAAAAnpiHhhJn+CiCHXL5PcZJ+aWC2NHenSo75B1T5zcqiB3tb06WHfKOafMb/X8QO9r77JD3TJvfqCB2tHs35de7uZr8RgWxo33IDnnPlPl5qwkECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQDAqiB3tQ3bIe6bMb1QQO9q9m/Lr3VxNfqOC2NHeZ4e8Z9r8RgWxo33PDnnP1Pndwsur17yjLb8bzg8AAAAAAAAAnp74URM72nbIG24iv2FB7GjvsUPeM21+RwtiR/soO+Q9U+Y3+ri7He3eTfn1bq4mv1FB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryc9bTSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEglFB7Gj3bsqvd3M1+Y0KYke7d1N+vZuryW9UEDvavZvy691cTX5HC2JH+4Ad8p5p8zvl5dV2tO2QP8ZTyA8AAAAAAAAAnpiHhhJn+CiCHXL5PcZJ+aWC2NHenSo75B1T5zcqiB3tb06WHfKOafMb/X8QO9r77JD3TJvfqCB2tHs35de7uZr8RgWxo33IDnnPlPl5qwkECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQDAqiB3tQ3bIe6bMb1QQO9q9m/Lr3VxNfqOC2NHeZ4e8Z9r8RgWxo33PDnnP1Pndwsur17yjLb8bzg8AAAC4ov8AwGjpQ+5xFXQAAAAASUVORK5CYII="
|
||||
},
|
||||
"diamond": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFF0lEQVR4nO3dMY4UZxAF4BpLThA52AfwBTiA5TtBYpHaCb6TZedcwAcAkyMSgnGwa9nDzv+2e/+ZVXXzfSm7VKlmHgvS0K8KAAAAaOFwz68/rapnVfWkqr698OzPVfWpqj5U1ccH/h6t9zsejz9W1auqelFVzy+3WlVV/V1Vb6vqzeFw+OOBv0fr+1WD/VJAnlfV9xdeauRd3bzga7Te73g8/lxVv1xnndNRVfX6cDj8uvL7Wt+vmuw3CsjTqvrhauuc91ct/5Om9X63Pzl+r/t/Ql/Ksap+WvGTpPX9qtF+3wy++Nl1d5me2X2/V/V44ajbWS9XfH33+7XZbxSQJ1dcZGTNzO77vbjaFpeZ2f1+bfYbBeTS/yBaYs3M7vtd+h/kS3y34mu736/NfqOAACUgEAkIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEo4B8ftQt1s/svt/aZ0BdwvsVX9v9fm32GwXk0xUXGVkzs/t+b6+2xWVmdr9fm/1GAflwxUVG1szsvt+bunmY22M53s5cqvv92uw3CsjHunkc42N5V+ue39p6v9snHL6uxwnJv48e/XPF97S+XzXaz8Orxy718OqXdfNQtzXPrVrifd38teo3D69+kEvsBwAAAAAAAABfmU1/1EQPuftN2HdPuh7yE+43Z1896XrIz3K/ObvqSddDPjfT/RbO3GpPuh7yuZnut3DmVnvS9ZDPzXS/hTM91QQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAINhqT7oe8rmZ7rdw5lZ70vWQz810v4Uzt9qTrod8bqb7LZy5yZ50PeR3uN+cffak6yF3vwl60gEAAAAAAABgtfhREz3a0x9FsN/Ge9yHAdGjfWJ1D3nZ7/822+N+NiB6tM9a3ENe9jtnkz3uo4+769Gem2m/uZlt3n+jgOjRnptpv7mZbd5/o4Do0Z6bab+5mW3ef55qAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQjAKiR3tupv3mZrZ5/40Cokd7bqb95ma2ef+NAqJHe26m/eZmtnn/nQ2IHu07VvWQl/2+tNke9yUPr9ajvdOHQ1fz/Tbw/gMAAAAAAACAr8x9RYlb+CiCHnf3e4hF90sB0aN9O6p22OPufieG9xsFRI/2FyNrRz3u7nfW2fuN/j+IHu1Te+txd7+FM0cB0aM9N9P95ma2ud8oIHq079pTj7v7LZzpqSYQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAsEoIHq079pTj7v7LZw5Coge7bmZ7jc3s839RgHRo31qbz3u7rdw5iggerT/s7sed/e7Y3i/PTy8unOPtvvt+H4AAAAAAAAA8PXZ9EdNqvl+esi3//putie9mu+nh/zEZl/fTfakV/P99JCftcnXd6s96d3300M+N7PNflvtSe++nx7yuZlt9ttqT3r3/fSQz81ss5+nmkAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBFvtSe++nx7yuZlt9ttqT3r3/fSQz81ss99We9K776eHfG5mm/022ZNezffTQ37HZl9fD68e00M+Z/evLwAAAPCI/gFIfqYbRE+aDAAAAABJRU5ErkJggg=="
|
||||
},
|
||||
"smalldiamond": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE7ElEQVR4nO3dMY5TVxQG4OOgNGioSbKAbIAFROwJmog2acieoqRnA1nAAA0VooDCKewospj78+5cP+s+z/e1PM/5da1/zEjWPVUAAADAFHbf+PebqnpaVY+r6vszz/5SVZ+q6n1Vfbznz5BPvvtalC8V5Ieq+unMoVpuq+pd52vk+598Y5r5vmu84KYuF66Os246npfvlHxjmvlaBXm6Xpamnpnyjc2Ub+HMVkEerxikpWemfGMz5Vs4s1WQc/9BtETPTPnGZsq3cGarIEApCEQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCQasgXy6aon+mfGMz5Vs4s1WQTysGaemZKd/YTPkWzmwV5P2KQVp6Zso3NlO+hTMfNR7+XFX7qnqyWpxTt1X1oeN5+U7JN6aZz+XVbfKNeQj5AAAAAAAAAOCB8VWTtuF8+/3+l6p6WVXP6rDW+JzeVdWbqnq92+3+uufPmPr8aoJ89qQv051vv9//WlW/rRPndFRVvdrtdr93vm7q86tJ8rUKclNVP68W527/1PLfNFPnO35y/Fnf/oQ+l31VPe/4JJn6/GqifPakrzPzZV2uHHWc9aLj+dnPb5p89qSvM/PZainOM3P285smnz3p68w89x/kS/zY8ezs5zdNPreaQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgE9qSvM7P3DqhzeNvx7OznN00+e9LXmflmtRTnmTn7+U2Tz570dWa+rsNlbpeyP85cavbzmyZfqyAf63Ad46XcVt/9rVPnO95w+KouU5L/rh79u+M1U59fTZTP5dVt57q8+kUdLnXrubdqibd1+G/VHy6vvhd70gEAAAAAAACg26a/amIPufMbcN170u0hP+H8xlzXnnR7yO/k/MZc1Z50e8jHZjq/hTO3uifdHvKxmc5v4cyt7km3h3xspvNbONOtJhAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCwVb3pNtDPjbT+S2cudU96faQj810fgtnbnVPuj3kYzOd38KZm9yTbg/5V5zfmOvck24PufMbYE86AAAAAAAAAHTb9FdNavJ89pBv//3d7J70mjyfPeQnNvv+bnJPek2ezx7yO23y/d3qnvTZ89lDPjZzmnxb3ZM+ez57yMdmTpNvq3vSZ89nD/nYzGnyudUEAgWBQEEgUBAIFAQCBYFAQSBQEAgUBAIFgUBBIFAQCBQEAgWBQEEgUBAIFAQCBYFAQSDY6p702fPZQz42c5p8W92TPns+e8jHZk6Tb6t70mfPZw/52Mxp8m1yT3pNns8e8q9s9v11eXWbPeRjrv79BQAAAAAAAICHx1dN2uQbcxX57ElfRr4xm83X+jbvTV0uXB1n3XQ8L98p+cY089mTvs5M+cZmTpPPnvR1Zso3NnOafPakrzNTvrGZ0+RzqwkECgKBgkCgIBAoCAQKAoGCQKAgECgIBAoCgYJAoCAQKAgECgKBgkCgIBAoCAQKAoGCQGBP+joz5RubOU0+e9LXmSnf2Mxp8tmTvs5M+cZmTpPvUePhz3XYv/1ktTinbqvqQ8fz8p2Sb0wzn8ur2+Qb8xDyAQAAAJfyL3WaU2vK5kXFAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"square": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFJElEQVR4nO3dQW4UVxAG4OpI2SD2kBwgF8gBRrkTbCy2yYbcBvZRss8FcgAb9ogNkiuLGRtZ7i5187rHr4fv2wamfqT6baGYVxEAAABA/zLzkJnvM/Mm13dz+uyDfPLtLl9mXm0QasxtZl7JJ99u8uWxubdnCngXcnaT5ZPvXPl+mMj4OiKGuX+gFQwR8WrBr5fvIfnaTOabKsiv22WZtGSmfG0z5Zs5c7SlmZnbZhk3DMOsrxryjZOvzVi+qe8gQCgIlBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBApTBflw1hRHNwt+rXyPyddmNN9UQf7dMMiUJTPla5sp38yZUwV5GxHnfFkiTzPnku8h+doszXf/9OM5XrdreZpSPvmeJN9dyENmvsvM6w2CXZ8+u/VxY/nke5J8AAAAAAAAAPD9KU9inf43/Os43m97ufLsD3H8Ccq3wzD8/Y2f8TwiXkTEs4j4ca1gJ18i4nNEfIyIT9/4GfI15Oth/yYLkscf4Pp95VCjoyLizTAMfyz8fS8j4ucN8oy5juX/RkG+rxbn62X/po54HiLir6n/voGMiN8WfCd5HhG/bJhnzH8x/yuhfI/NztfT/u31TvqLrYKsNFO+tpnd7N9e76Q/2yzFOjPla5vZzf5NFWTtvxDN8dOCX7v2XyjXnilf28xu9s+rJlBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgU9non/ctmKdaZKV/bzG72b6930j9vlmKdmfK1zexm//Z6J/3jVkFWmilf28xu9m+0IKcX5t7EeULePf34z4Lf8ymOz1mey3Use19WvocW5etp/+Y8Xv0qjo9qLXm3ao6bOH5b+9Pj1d/k4vPtYP8AAAAAAAAA4DvjTvq0i/9Rjug8Xw/75076PBd3hzw6z9fL/rmTPt/F3CGPzvP1tH/upG8zU762md3snzvp28yUr21mN/vnTvo2M+Vrm9nN/nnVBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoCBQWBgoJAQUGgoCBQUBAoKAgUFAQKCgIFBYGCO+nbzJSvbWY3++dO+jYz5Wub2c3+uZO+zUz52mZ2s3/upM9zUXfIo/N8Pe2fO+nTLv5x6Og83w72DwAAAAAAAAC+M+6kT7v4H+WIzvP1sH/upM9zcXfIo/N8veyfO+nzXcwd8ug8X0/75076NjPla5vZzf65k77NTPnaZnazf+6kbzNTvraZ3eyfV02goCBQUBAoKAgUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKLiTvs1M+dpmdrN/7qRvM1O+tpnd7J876dvMlK9tZjf75076PBd1hzw6z9fT/rmTPu3iH4eOzvPtYP8AAAAAAAAAgK8y85CZ7zPzJtd3c/rsg3zy7S5fZl5tEGrMbR5vYssn3z7y5bG5t2cKeBdydpPlk+9c+fZ6J12+h+Rrc3F30uVrmynfzJmjLc3Mc/5rrnvDMMz6qiHfOPnajOXzqgkUFAQKCgIFBYGCgkBBQaCgIFBQECgoCBQUBAoKAgUFgYKCQEFBoKAgUFAQKCgIFBQECgoChb3eSZfvMfnaXNSddPnaZso3c+Ze76TL95B8bZbmu3/68Ryv27U8TSmffE+S7y7kITPfZeb1BsGuT5/d+rixfPI9ST4AAADgjP4Hm2pLjkVf1VMAAAAASUVORK5CYII="
|
||||
},
|
||||
"smallsquare": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE6ElEQVR4nO3dP44URxQH4DdGTtAQY3wAX4ADWNwJEkRqEnwny865gA+wQEKECCAYghkbWrP1tmqqe9TV+33p9uz7qbd/+0earRcBAAAArMLujo/vI+JxRDyMiJ9nnv01Ij5HxIeI+HTh55BPvktV5csK8ktE/DpzqJKbiHjf+Br5vpOvTzHfT4UX7ON64eI0a99wvXxT8vUp5isV5PFyWYpaZsrXN1O+ypmlgjxcMEhJy0z5+mbKVzmzVJC5/yCq0TJTvr6Z8lXOLBUECAWBlIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQKJUkK9XTdE+U76+mfJVziwV5POCQUpaZsrXN1O+ypmlgnxYMEhJy0z5+mbKVznzQeHiLxFxiIhHi8WZuomIjw3XyzclX59iPodXl8nX5z7kAwAAAAAAAIB7Zui3mhwOh98j4kVEPI3j2uA5vY+ItxHxZrfb/X3JJ5CvL1+s4Pkbdk/64XB4GRF/LBNnOioiXu12u9dNL5Lv/1FxQb5YyfNXKsg+In5bLM7t/o3KnySn73x/xd0/AedyiIhntd8J5TsfGQ35YkXP36h70l/E9b64cZr1vOF6+aZa863m+Rt1T/rTxVLMM1O+vpmref5G3ZM+9x+UNZ40XCvfuZZ8q3n+nGoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQGLUPelNZ2jN5F3DtfKda8m3mudv1D3pbxdLMc9M+fpmrub5G3VP+ps4HkZ2LYfTzFryTbXmW83zVyrIpzgex3gtN9FwPu/phL5XcZ0v8n9HZ/5T+wL5JprzxYqevy0cXv08joeStZy7VONdHH8t+LPzcGj5Bj68GgAAAAAAAAD40RbeamLPt/t3CXvSZzL0nu8S92/CnvROw+75vo37dyt70jsMu+e7wP2rnGlP+jIz3b++mau5f/ak1xtyz3eB+1c506kmkFAQSCgIJBQEEgoCCQWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCTsSa835J7vAvevcqY96cvMdP/6Zq7m/tmTXmfYPd8F7l/lTHvS7zb0nu/buH9n7Em/wOb3fLt/9qQDAAAAAAAAQJstvNVktXu+5bMnfS6b2/Mt3/dRYU/6LDaz51u+85FhT3q3Le35lm/KnvQZbGnPt3x9M1fz/NmTXq/l/yXkO2dPOmyNgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIKEgkFAQSCgIJBQEEgoCCQWBhIJAQkEgYU96vZY93/Kdsye905b2fMvXN3M1z5896XVa93zLN2VPeqdN7fmWb8Ke9Attfs+3fPakAwAAAAAAAMC2DP1Wk5BPvstte096yPcj+foU85XezbuP64WL06x9w/XyTcnXp5hv1D3p8vXNlK9y5qh70uXrmylf5cxR96TL1zdTvsqZTjWBhIJAQkEgoSCQUBBIKAgkFAQSCgIJBYGEgkBCQSChIJBQEEgoCCQUBBIKAgkFgYSCQEJBIDHqnnT5+mbKVzlz1D3p8vXNlK9y5qh70uXrmylf5cwHhYu/xHG/9aPF4kzdRMTHhuvlm5KvTzGfw6vL5OtzH/IBAAAA1/IN7YSWk669SX0AAAAASUVORK5CYII="
|
||||
},
|
||||
"scissors": {
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFUUlEQVR4nO3dMW6cRRgG4G+RaCL6AAfgAjkA4k5Jg9JCE+6EoM8FOEBC+ihNiqVYU0TZeT3rnd/6/vXztB57Ps3odWTFnrcKAAAAaOGQPng8Hn+uqldV9aKqvl+8979V9baq3hwOh78e8gW6z1dV31XV86p6VlXfrhrszueq+lRVH6rq4wO/Ruv5OtzvMCDH4/HXqvpt8VBnt6qq14fD4feLPqn5fHW60B83mOecd3W68Eu0nq/L/Z4NyF1y/xx9fAPHqvpl9jt19/nq9J35pw3nOeefmv9O3Xq+Tvf7zeATXtXjDVd3e728YH33+Z5vNciiPbvP1+Z+RwF5sd0sQ5fs2X2+Z5tNsWbP7vO1ud9RQFb/QDTjhwvWdp9v9Q+8q/fsPl+b+x0FBCgBgUhAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgGAXk0jeWVnh/wdru833ebIo1e3afr839jgLydsNBRi7Zs/t8nzabYs2e3edrc7+jgLyp02Naj+V4t+es7vN92GqQRXt2n6/N/Z4NyN0Lc6/rcYb8/+nHv2c/oft8dXpB8N1G85zzri57/7b1fJ3ud+bx6pd1elTrknehZryv0z9rf1z5eHXb+ar549DVfL4d3C8AAAAAAAAAPDF60sduvifd+d1/fnrSJ7aqG+xJd35fGJ6fnvQ5N9WT7vzOOnt+etLn3FpPuvOb3FNP+jZ76iG/bs8256cnfd4t9aQ7v8k9vWoCgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBDoSZ93Sz3pzm9yTz3p2+yph/y6Pducn570ObfWk+78JvfUk36/m+tJd35fGZ6fnvSxm+9Jd35X98wDAAAAAAAAwBNzX5Fj9//qbz2fHvL9328KSIue6qD1fHrIv7Db+x0FpE1P9UDr+fSQn7XL+x39PUibnuoFa1fRQ36dXd7vKCBteqoXrF1FD/l1dnm/o4C06alesHYVPeTX2eX9etUEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAYBaRNT/WCtavoIb/OLu93FJA2PdUL1q6ih/w6u7zfUUDa9FQvWLuKHvLr7PJ+RwFp01M90Ho+PeRf2e39erx6TA/5dW7+fgEAAAAAAADg6Ym/atK957v7fNX8VyWc3xU96d17vrvPV016vkec3xcu60nv3vPdfb5q1PN9jvM766Ke9O49393na9PzPeD8JvccBaR7z3f3+dr0fA84v8k9RwHp3vPdfb42Pd8Dzm9yT6+aQCAgEAgIBAICgYBAICAQCAgEAgKBgEAgIBAICAQCAoGAQCAgEAgIBAICgYBAICAQCAgEo4B07/nuPl+bnu8B5ze55ygg3Xu+u8/Xpud7wPlN7jkKSPee7+7zten5HnB+k3ueDUj3nu/u81Wjnu9znN9XHtaT3r3nu/t81eDx5cT56UkHAAAAAAAAgMvoSR+7iZ7ve7Ser8P96kmf2Kp23PMdtJ6vy/3qSZ+z257vgdbzdbpfPelzdtvzvWDtKrvscdeTvs2ebXq+F6xdZZc97nrS5+2y53vB2lV22ePuVRMIBAQCAYFAQCAQEAgEBAIBgUBAIBAQCAQEAgGBQEAgEBAIBAQCAYFAQCAQEAgEBAIBgUBP+rxd9nwvWLvKLnvc9aRvs2ebnu8Fa1fZZY+7nvQ5u+35XrB2lV32uOtJv9+ue74HWs/X6X71pI89hZ7v1vPt4H4BAACAx/IfV5v6DSxvZ+4AAAAASUVORK5CYII="
|
||||
}
|
||||
}
|
@ -27,124 +27,124 @@ THE SOFTWARE.
|
||||
|
||||
enum IconNames {
|
||||
//% block="heart"
|
||||
//% blockImage=1
|
||||
//% jres=icons.heart
|
||||
Heart = 0,
|
||||
//% block="small heart"
|
||||
//% blockImage=1
|
||||
//% jres=icons.smallheart
|
||||
SmallHeart,
|
||||
//% block="yes"
|
||||
//% blockImage=1
|
||||
//% jres=icons.yes
|
||||
Yes,
|
||||
//% block="no"
|
||||
//% blockImage=1
|
||||
//% jres=icons.no
|
||||
No,
|
||||
//% block="happy"
|
||||
//% blockImage=1
|
||||
//% jres=icons.happy
|
||||
Happy,
|
||||
//% block="sad"
|
||||
//% blockImage=1
|
||||
//% jres=icons.sad
|
||||
Sad,
|
||||
//% block="confused"
|
||||
//% blockImage=1
|
||||
//% jres=icons.confused
|
||||
Confused,
|
||||
//% block="angry"
|
||||
//% blockImage=1
|
||||
//% jres=icons.angry
|
||||
Angry,
|
||||
//% block="asleep"
|
||||
//% blockImage=1
|
||||
//% jres=icons.asleep
|
||||
Asleep,
|
||||
//% block="surprised"
|
||||
//% blockImage=1
|
||||
//% jres=icons.surprised
|
||||
Surprised,
|
||||
//% block="silly"
|
||||
//% blockImage=1
|
||||
//% jres=icons.silly
|
||||
Silly,
|
||||
//% block="fabulous"
|
||||
//% blockImage=1
|
||||
//% jres=icons.fabulous
|
||||
Fabulous,
|
||||
//% block="meh"
|
||||
//% blockImage=1
|
||||
//% jres=icons.meh
|
||||
Meh,
|
||||
//% block="t-shirt"
|
||||
//% blockImage=1
|
||||
//% jres=icons.tshirt
|
||||
TShirt,
|
||||
//% block="roller skate"
|
||||
//% blockImage=1
|
||||
//% jres=icons.rollerskate
|
||||
Rollerskate,
|
||||
//% block="duck"
|
||||
//% blockImage=1
|
||||
//% jres=icons.duck
|
||||
Duck,
|
||||
//% block="house"
|
||||
//% blockImage=1
|
||||
//% jres=icons.house
|
||||
House,
|
||||
//% block="tortoise"
|
||||
//% blockImage=1
|
||||
//% jres=icons.tortoise
|
||||
Tortoise,
|
||||
//% block="butterfly"
|
||||
//% blockImage=1
|
||||
//% jres=icons.butterfly
|
||||
Butterfly,
|
||||
//% block="stick figure"
|
||||
//% blockImage=1
|
||||
//% jres=icons.stickfigure
|
||||
StickFigure,
|
||||
//% block="ghost"
|
||||
//% blockImage=1
|
||||
//% jres=icons.ghost
|
||||
Ghost,
|
||||
//% block="sword"
|
||||
//% blockImage=1
|
||||
//% jres=icons.sword
|
||||
Sword,
|
||||
//% block="giraffe"
|
||||
//% blockImage=1
|
||||
//% jres=icons.giraffe
|
||||
Giraffe,
|
||||
//% block="skull"
|
||||
//% blockImage=1
|
||||
//% jres=icons.skull
|
||||
Skull,
|
||||
//% block="umbrella"
|
||||
//% blockImage=1
|
||||
//% jres=icons.umbrella
|
||||
Umbrella,
|
||||
//% block="snake"
|
||||
//% blockImage=1
|
||||
//% jres=icons.snake
|
||||
Snake,
|
||||
//% block="rabbit"
|
||||
//% blockImage=1
|
||||
//% jres=icons.rabbit
|
||||
Rabbit,
|
||||
//% block="cow"
|
||||
//% blockImage=1
|
||||
//% jres=icons.cow
|
||||
Cow,
|
||||
//% block="quarter note"
|
||||
//% blockImage=1
|
||||
//% jres=icons.quarternote
|
||||
QuarterNote,
|
||||
//% block="eigth note"
|
||||
//% blockImage=1
|
||||
//% jres=icons.eigthnote
|
||||
EigthNote,
|
||||
//% block="pitchfork"
|
||||
//% blockImage=1
|
||||
//% jres=icons.pitchfork
|
||||
Pitchfork,
|
||||
//% block="target"
|
||||
//% blockImage=1
|
||||
//% jres=icons.target
|
||||
Target,
|
||||
//% block="triangle"
|
||||
//% blockImage=1
|
||||
//% jres=icons.triangle
|
||||
Triangle,
|
||||
//% block="left triangle"
|
||||
//% blockImage=1
|
||||
//% jres=icons.lefttriangle
|
||||
LeftTriangle,
|
||||
//% block="chess board"
|
||||
//% blockImage=1
|
||||
//% jres=icons.chessboard
|
||||
Chessboard,
|
||||
//% block="diamond"
|
||||
//% blockImage=1
|
||||
//% jres=icons.diamond
|
||||
Diamond,
|
||||
//% block="small diamond"
|
||||
//% blockImage=1
|
||||
//% jres=icons.smalldiamond
|
||||
SmallDiamond,
|
||||
//% block="square"
|
||||
//% blockImage=1
|
||||
//% jres=icons.square
|
||||
Square,
|
||||
//% block="small square"
|
||||
//% blockImage=1
|
||||
//% jres=icons.smallsquare
|
||||
SmallSquare,
|
||||
//% block="scissors"
|
||||
//% blockImage=1
|
||||
//% jres=icons.scissors
|
||||
Scissors
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ namespace basic {
|
||||
|
||||
/**
|
||||
* Draws the selected icon on the LED screen
|
||||
* @param icon the predifined icon id
|
||||
* @param icon the predefined icon id
|
||||
* @param interval the amount of time (milliseconds) to show the icon. Default is 600.
|
||||
*/
|
||||
//% weight=90 blockGap=8
|
||||
@ -179,16 +179,17 @@ namespace basic {
|
||||
//% block="show icon %i" icon="\uf00a"
|
||||
//% parts="ledmatrix"
|
||||
//% help=basic/show-icon
|
||||
//% i.fieldEditor="gridpicker"
|
||||
//% i.fieldOptions.width="400" i.fieldOptions.columns="5"
|
||||
//% i.fieldOptions.itemColour="black" i.fieldOptions.tooltips="true"
|
||||
//% icon.fieldEditor="imagedropdown"
|
||||
//% icon.fieldOptions.columns="5"
|
||||
//% icon.fieldOptions.width="380"
|
||||
//% icon.fieldOptions.maxRows=4
|
||||
export function showIcon(icon: IconNames, interval = 600) {
|
||||
let res = images.iconImage(icon)
|
||||
res.showImage(0, interval)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an arrow on screent
|
||||
* Draws an arrow on the LED screen
|
||||
* @param direction the direction of the arrow
|
||||
* @param interval the amount of time (milliseconds) to show the icon. Default is 600.
|
||||
*/
|
||||
@ -213,49 +214,49 @@ namespace images {
|
||||
export function arrowImage(i: ArrowNames): Image {
|
||||
switch (i) {
|
||||
// compass directions
|
||||
case ArrowNames.North: return images.createImage(`
|
||||
case ArrowNames.North: return images.createImage(`
|
||||
. . # . .
|
||||
. # # # .
|
||||
# . # . #
|
||||
. . # . .
|
||||
. . # . .`);
|
||||
case ArrowNames.NorthEast: return images.createImage(`
|
||||
case ArrowNames.NorthEast: return images.createImage(`
|
||||
. . # # #
|
||||
. . . # #
|
||||
. . # . #
|
||||
. # . . .
|
||||
# . . . .`);
|
||||
case ArrowNames.East: return images.createImage(`
|
||||
case ArrowNames.East: return images.createImage(`
|
||||
. . # . .
|
||||
. . . # .
|
||||
# # # # #
|
||||
. . . # .
|
||||
. . # . .`);
|
||||
case ArrowNames.SouthEast: return images.createImage(`
|
||||
case ArrowNames.SouthEast: return images.createImage(`
|
||||
# . . . .
|
||||
. # . . .
|
||||
. . # . #
|
||||
. . . # #
|
||||
. . # # #`);
|
||||
case ArrowNames.South: return images.createImage(`
|
||||
case ArrowNames.South: return images.createImage(`
|
||||
. . # . .
|
||||
. . # . .
|
||||
# . # . #
|
||||
. # # # .
|
||||
. . # . .`);
|
||||
case ArrowNames.SouthWest: return images.createImage(`
|
||||
case ArrowNames.SouthWest: return images.createImage(`
|
||||
. . . . #
|
||||
. . . # .
|
||||
# . # . .
|
||||
# # . . .
|
||||
# # # . .`);
|
||||
case ArrowNames.West: return images.createImage(`
|
||||
case ArrowNames.West: return images.createImage(`
|
||||
. . # . .
|
||||
. # . . .
|
||||
# # # # #
|
||||
. # . . .
|
||||
. . # . .`);
|
||||
case ArrowNames.NorthWest: return images.createImage(`
|
||||
case ArrowNames.NorthWest: return images.createImage(`
|
||||
# # # . .
|
||||
# # . . .
|
||||
# . # . .
|
||||
@ -274,9 +275,10 @@ namespace images {
|
||||
//% weight=50 blockGap=8
|
||||
//% help=images/icon-image
|
||||
//% blockId=builtin_image block="icon image %i"
|
||||
//% i.fieldEditor="gridpicker"
|
||||
//% i.fieldOptions.width="400" i.fieldOptions.columns="5"
|
||||
//% i.fieldOptions.itemColour="black" i.fieldOptions.tooltips="true"
|
||||
//% i.fieldEditor="imagedropdown"
|
||||
//% i.fieldOptions.columns="5"
|
||||
//% i.fieldOptions.width="380"
|
||||
//% i.fieldOptions.maxRows=4
|
||||
export function iconImage(i: IconNames): Image {
|
||||
switch (i) {
|
||||
case IconNames.Heart: return images.createImage(`
|
||||
|
@ -1,156 +1,183 @@
|
||||
#include "pxt.h"
|
||||
|
||||
PXT_VTABLE(RefMImage, ValType::Object)
|
||||
|
||||
RefMImage::RefMImage(ImageData *d) : PXT_VTABLE_INIT(RefMImage), img(d) {
|
||||
img->incr();
|
||||
}
|
||||
|
||||
void RefMImage::destroy(RefMImage *t) {
|
||||
t->img->decr();
|
||||
}
|
||||
|
||||
void RefMImage::print(RefMImage *t) {
|
||||
DMESG("RefMImage %p r=%d size=%d x %d", t, t->refcnt, img->width, img->height);
|
||||
}
|
||||
|
||||
void RefMImage::makeWritable() {
|
||||
if (img->isReadOnly()) {
|
||||
MicroBitImage i(img);
|
||||
img = i.clone().leakData();
|
||||
}
|
||||
}
|
||||
|
||||
void RefMImage::scan(RefMImage *t) {}
|
||||
|
||||
unsigned RefMImage::gcsize(RefMImage *t) {
|
||||
return (sizeof(*t) + 3) >> 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creation, manipulation and display of LED images.
|
||||
*/
|
||||
//% color=#5C2D91 weight=31 icon="\uf03e"
|
||||
* Creation, manipulation and display of LED images.
|
||||
*/
|
||||
//% color=#7600A8 weight=31 icon="\uf03e"
|
||||
//% advanced=true
|
||||
namespace images {
|
||||
/**
|
||||
* Creates an image that fits on the LED screen.
|
||||
*/
|
||||
//% weight=75 help=images/create-image
|
||||
//% blockId=device_build_image block="create image"
|
||||
//% parts="ledmatrix"
|
||||
Image createImage(ImageLiteral leds) {
|
||||
return MicroBitImage(imageBytes(leds)).clone().leakData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an image with 2 frames.
|
||||
*/
|
||||
//% weight=74 help=images/create-big-image
|
||||
//% blockId=device_build_big_image block="create big image" imageLiteral=2
|
||||
//% parts="ledmatrix"
|
||||
Image createBigImage(ImageLiteral leds) {
|
||||
return createImage(leds);
|
||||
}
|
||||
/**
|
||||
* Creates an image that fits on the LED screen.
|
||||
*/
|
||||
//% weight=75 help=images/create-image
|
||||
//% blockId=device_build_image block="create image"
|
||||
//% parts="ledmatrix"
|
||||
Image createImage(ImageLiteral_ leds) {
|
||||
return NEW_GC(RefMImage, imageBytes(leds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an image with 2 frames.
|
||||
*/
|
||||
//% weight=74 help=images/create-big-image
|
||||
//% blockId=device_build_big_image block="create big image" imageLiteral=2
|
||||
//% parts="ledmatrix"
|
||||
Image createBigImage(ImageLiteral_ leds) {
|
||||
return createImage(leds);
|
||||
}
|
||||
} // namespace images
|
||||
|
||||
namespace ImageMethods {
|
||||
/**
|
||||
* Plots the image at a given column to the screen
|
||||
*/
|
||||
//% help=images/plot-image
|
||||
//% parts="ledmatrix"
|
||||
void plotImage(Image i, int xOffset = 0) {
|
||||
uBit.display.print(MicroBitImage(i), -xOffset, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an frame from the image at offset ``x offset``.
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/show-image weight=80 blockNamespace=images
|
||||
//% blockId=device_show_image_offset block="show image %sprite|at offset %offset" blockGap=8
|
||||
//% parts="ledmatrix" async
|
||||
void showImage(Image sprite, int xOffset, int interval = 400) {
|
||||
uBit.display.print(MicroBitImage(sprite), -xOffset, 0, 0, interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the ``index``-th frame of the image on the screen.
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/plot-frame weight=80
|
||||
//% parts="ledmatrix"
|
||||
void plotFrame(Image i, int xOffset) {
|
||||
// TODO showImage() used in original implementation
|
||||
plotImage(i, xOffset * 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls an image .
|
||||
* @param frameOffset x offset moved on each animation step, eg: 1, 2, 5
|
||||
* @param interval time between each animation step in milli seconds, eg: 200
|
||||
*/
|
||||
//% help=images/scroll-image weight=79 async blockNamespace=images
|
||||
//% blockId=device_scroll_image block="scroll image %sprite|with offset %frameoffset|and interval (ms) %delay" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
void scrollImage(Image id, int frameOffset, int interval) {
|
||||
MicroBitImage i(id);
|
||||
uBit.display.animate(i, interval, frameOffset, MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets all pixels off.
|
||||
*/
|
||||
//% help=images/clear
|
||||
//% parts="ledmatrix"
|
||||
void clear(Image i) {
|
||||
MicroBitImage(i).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific pixel brightness at a given position
|
||||
*/
|
||||
//%
|
||||
//% parts="ledmatrix"
|
||||
void setPixelBrightness(Image i, int x, int y, int value) {
|
||||
MicroBitImage(i).setPixelValue(x, y, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the pixel brightness ([0..255]) at a given position
|
||||
*/
|
||||
//%
|
||||
//% parts="ledmatrix"
|
||||
int pixelBrightness(Image i, int x, int y) {
|
||||
int pix = MicroBitImage(i).getPixelValue(x, y);
|
||||
if (pix < 0) return 0;
|
||||
return pix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the width in columns
|
||||
*/
|
||||
//% help=functions/width
|
||||
int width(Image i) {
|
||||
return i->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height in rows (always 5)
|
||||
*/
|
||||
//%
|
||||
int height(Image i) {
|
||||
return i->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pixel state at position ``(x,y)``
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param value TODO
|
||||
*/
|
||||
//% help=images/set-pixel
|
||||
//% parts="ledmatrix"
|
||||
void setPixel(Image i, int x, int y, bool value) {
|
||||
setPixelBrightness(i, x, y, value ? 255 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pixel state at position ``(x,y)``
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
*/
|
||||
//% help=images/pixel
|
||||
//% parts="ledmatrix"
|
||||
bool pixel(Image i, int x, int y) {
|
||||
return pixelBrightness(i, x, y) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows a particular frame of the image strip.
|
||||
* @param frame TODO
|
||||
*/
|
||||
//% weight=70 help=images/show-frame
|
||||
//% parts="ledmatrix"
|
||||
void showFrame(Image i, int frame, int interval = 400) {
|
||||
showImage(i, frame * 5, interval);
|
||||
}
|
||||
/**
|
||||
* Plots the image at a given column to the screen
|
||||
*/
|
||||
//% help=images/plot-image
|
||||
//% parts="ledmatrix"
|
||||
void plotImage(Image i, int xOffset = 0) {
|
||||
uBit.display.print(MicroBitImage(i->img), -xOffset, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an frame from the image at offset ``x offset``.
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/show-image weight=80 blockNamespace=images
|
||||
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset"
|
||||
//% blockGap=8 parts="ledmatrix" async
|
||||
void showImage(Image sprite, int xOffset, int interval = 400) {
|
||||
uBit.display.print(MicroBitImage(sprite->img), -xOffset, 0, 0, interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the ``index``-th frame of the image on the screen.
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/plot-frame weight=80
|
||||
//% parts="ledmatrix"
|
||||
void plotFrame(Image i, int xOffset) {
|
||||
// TODO showImage() used in original implementation
|
||||
plotImage(i, xOffset * 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls an image .
|
||||
* @param frameOffset x offset moved on each animation step, eg: 1, 2, 5
|
||||
* @param interval time between each animation step in milli seconds, eg: 200
|
||||
*/
|
||||
//% help=images/scroll-image weight=79 async blockNamespace=images
|
||||
//% blockId=device_scroll_image
|
||||
//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay"
|
||||
//% blockGap=8 parts="ledmatrix"
|
||||
void scrollImage(Image id, int frameOffset, int interval) {
|
||||
MicroBitImage i(id->img);
|
||||
uBit.display.animate(i, interval, frameOffset, MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all pixels off.
|
||||
*/
|
||||
//% help=images/clear
|
||||
//% parts="ledmatrix"
|
||||
void clear(Image i) {
|
||||
i->makeWritable();
|
||||
MicroBitImage(i->img).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific pixel brightness at a given position
|
||||
*/
|
||||
//%
|
||||
//% parts="ledmatrix"
|
||||
void setPixelBrightness(Image i, int x, int y, int value) {
|
||||
i->makeWritable();
|
||||
MicroBitImage(i->img).setPixelValue(x, y, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pixel brightness ([0..255]) at a given position
|
||||
*/
|
||||
//%
|
||||
//% parts="ledmatrix"
|
||||
int pixelBrightness(Image i, int x, int y) {
|
||||
int pix = MicroBitImage(i->img).getPixelValue(x, y);
|
||||
if (pix < 0)
|
||||
return 0;
|
||||
return pix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width in columns
|
||||
*/
|
||||
//% help=functions/width
|
||||
int width(Image i) {
|
||||
return i->img->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height in rows (always 5)
|
||||
*/
|
||||
//%
|
||||
int height(Image i) {
|
||||
return i->img->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pixel state at position ``(x,y)``
|
||||
* @param x pixel column
|
||||
* @param y pixel row
|
||||
* @param value pixel state
|
||||
*/
|
||||
//% help=images/set-pixel
|
||||
//% parts="ledmatrix"
|
||||
void setPixel(Image i, int x, int y, bool value) {
|
||||
setPixelBrightness(i, x, y, value ? 255 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pixel state at position ``(x,y)``
|
||||
* @param x pixel column
|
||||
* @param y pixel row
|
||||
*/
|
||||
//% help=images/pixel
|
||||
//% parts="ledmatrix"
|
||||
bool pixel(Image i, int x, int y) {
|
||||
return pixelBrightness(i, x, y) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a particular frame of the image strip.
|
||||
* @param frame image frame to show
|
||||
*/
|
||||
//% weight=70 help=images/show-frame
|
||||
//% parts="ledmatrix"
|
||||
void showFrame(Image i, int frame, int interval = 400) {
|
||||
showImage(i, frame * 5, interval);
|
||||
}
|
||||
} // namespace ImageMethods
|
@ -60,56 +60,67 @@ enum class Gesture {
|
||||
* Raised when shaken
|
||||
*/
|
||||
//% block=shake
|
||||
//% jres=gestures.shake
|
||||
Shake = MICROBIT_ACCELEROMETER_EVT_SHAKE,
|
||||
/**
|
||||
* Raised when the logo is upward and the screen is vertical
|
||||
*/
|
||||
//% block="logo up"
|
||||
//% jres=gestures.tiltforward
|
||||
LogoUp = MICROBIT_ACCELEROMETER_EVT_TILT_UP,
|
||||
/**
|
||||
* Raised when the logo is downward and the screen is vertical
|
||||
*/
|
||||
//% block="logo down"
|
||||
//% jres=gestures.tiltbackwards
|
||||
LogoDown = MICROBIT_ACCELEROMETER_EVT_TILT_DOWN,
|
||||
/**
|
||||
* Raised when the screen is pointing down and the board is horizontal
|
||||
*/
|
||||
//% block="screen up"
|
||||
//% jres=gestures.frontsideup
|
||||
ScreenUp = MICROBIT_ACCELEROMETER_EVT_FACE_UP,
|
||||
/**
|
||||
* Raised when the screen is pointing up and the board is horizontal
|
||||
*/
|
||||
//% block="screen down"
|
||||
//% jres=gestures.backsideup
|
||||
ScreenDown = MICROBIT_ACCELEROMETER_EVT_FACE_DOWN,
|
||||
/**
|
||||
* Raised when the screen is pointing left
|
||||
*/
|
||||
//% block="tilt left"
|
||||
//% jres=gestures.tiltleft
|
||||
TiltLeft = MICROBIT_ACCELEROMETER_EVT_TILT_LEFT,
|
||||
/**
|
||||
* Raised when the screen is pointing right
|
||||
*/
|
||||
//% block="tilt right"
|
||||
//% jres=gestures.tiltright
|
||||
TiltRight = MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT,
|
||||
/**
|
||||
* Raised when the board is falling!
|
||||
*/
|
||||
//% block="free fall"
|
||||
//% jres=gestures.freefall
|
||||
FreeFall = MICROBIT_ACCELEROMETER_EVT_FREEFALL,
|
||||
/**
|
||||
* Raised when a 3G shock is detected
|
||||
*/
|
||||
//% block="3g"
|
||||
//% jres=gestures.impact3g
|
||||
ThreeG = MICROBIT_ACCELEROMETER_EVT_3G,
|
||||
/**
|
||||
* Raised when a 6G shock is detected
|
||||
*/
|
||||
//% block="6g"
|
||||
//% jres=gestures.impact6g
|
||||
SixG = MICROBIT_ACCELEROMETER_EVT_6G,
|
||||
/**
|
||||
* Raised when a 8G shock is detected
|
||||
*/
|
||||
//% block="8g"
|
||||
//% jres=gestures.impact8g
|
||||
EightG = MICROBIT_ACCELEROMETER_EVT_8G
|
||||
};
|
||||
|
||||
@ -155,7 +166,7 @@ namespace input {
|
||||
* @param button the button that needs to be pressed
|
||||
* @param body code to run when event is raised
|
||||
*/
|
||||
//% help=input/on-button-pressed weight=85 blockGap=8
|
||||
//% help=input/on-button-pressed weight=85 blockGap=16
|
||||
//% blockId=device_button_event block="on button|%NAME|pressed"
|
||||
//% parts="buttonpair"
|
||||
void onButtonPressed(Button button, Action body) {
|
||||
@ -167,10 +178,10 @@ namespace input {
|
||||
* @param gesture the type of gesture to track, eg: Gesture.Shake
|
||||
* @param body code to run when gesture is raised
|
||||
*/
|
||||
//% help=input/on-gesture weight=84 blockGap=8
|
||||
//% help=input/on-gesture weight=84 blockGap=16
|
||||
//% blockId=device_gesture_event block="on |%NAME"
|
||||
//% parts="accelerometer"
|
||||
//% NAME.fieldEditor="gridpicker" NAME.fieldOptions.columns=4
|
||||
//% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4
|
||||
void onGesture(Gesture gesture, Action body) {
|
||||
int gi = (int)gesture;
|
||||
if (gi == MICROBIT_ACCELEROMETER_EVT_3G && uBit.accelerometer.getRange() < 3)
|
||||
@ -180,12 +191,27 @@ namespace input {
|
||||
registerWithDal(MICROBIT_ID_GESTURE, gi, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a gesture is currently detected.
|
||||
* @param gesture the type of gesture to detect, eg: Gesture.Shake
|
||||
*/
|
||||
//% help=input/is-gesture weight=10 blockGap=8
|
||||
//% blockId=deviceisgesture block="is %gesture gesture"
|
||||
//% parts="accelerometer"
|
||||
//% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4
|
||||
bool isGesture(Gesture gesture) {
|
||||
// turn on acceleration
|
||||
uBit.accelerometer.getX();
|
||||
int gi = (int)gesture;
|
||||
return uBit.accelerometer.getGesture() == gi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a pin is touched and released again (while also touching the GND pin).
|
||||
* @param name the pin that needs to be pressed, eg: TouchPin.P0
|
||||
* @param body the code to run when the pin is pressed
|
||||
*/
|
||||
//% help=input/on-pin-pressed weight=83
|
||||
//% help=input/on-pin-pressed weight=83 blockGap=32
|
||||
//% blockId=device_pin_event block="on pin %name|pressed"
|
||||
void onPinPressed(TouchPin name, Action body) {
|
||||
auto pin = getPin((int)name);
|
||||
@ -201,7 +227,7 @@ namespace input {
|
||||
* @param name the pin that needs to be released, eg: TouchPin.P0
|
||||
* @param body the code to run when the pin is released
|
||||
*/
|
||||
//% help=input/on-pin-released weight=6 blockGap=8
|
||||
//% help=input/on-pin-released weight=6 blockGap=16
|
||||
//% blockId=device_pin_released block="on pin %NAME|released"
|
||||
//% advanced=true
|
||||
void onPinReleased(TouchPin name, Action body) {
|
||||
@ -220,7 +246,7 @@ namespace input {
|
||||
//% help=input/button-is-pressed weight=60
|
||||
//% block="button|%NAME|is pressed"
|
||||
//% blockId=device_get_button2
|
||||
//% blockGap=8
|
||||
//% icon="\uf192" blockGap=8
|
||||
//% parts="buttonpair"
|
||||
bool buttonIsPressed(Button button) {
|
||||
if (button == Button::A)
|
||||
@ -253,7 +279,7 @@ namespace input {
|
||||
|
||||
/**
|
||||
* Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)
|
||||
* @param dimension TODO
|
||||
* @param dimension x, y, or z dimension, eg: Dimension.X
|
||||
*/
|
||||
//% help=input/acceleration weight=58
|
||||
//% blockId=device_acceleration block="acceleration (mg)|%NAME" blockGap=8
|
||||
@ -303,7 +329,7 @@ namespace input {
|
||||
|
||||
/**
|
||||
* The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees.
|
||||
* @param kind TODO
|
||||
* @param kind pitch or roll
|
||||
*/
|
||||
//% help=input/rotation weight=52
|
||||
//% blockId=device_get_rotation block="rotation (°)|%NAME" blockGap=8
|
||||
@ -318,7 +344,7 @@ namespace input {
|
||||
|
||||
/**
|
||||
* Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.
|
||||
* @param dimension TODO
|
||||
* @param dimension the x, y, or z dimension, eg: Dimension.X
|
||||
*/
|
||||
//% help=input/magnetic-force weight=51
|
||||
//% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8
|
||||
@ -362,8 +388,9 @@ namespace input {
|
||||
*/
|
||||
//% help=input/calibrate-compass advanced=true
|
||||
//% blockId="input_compass_calibrate" block="calibrate compass"
|
||||
void calibrateCompass() {
|
||||
uBit.compass.calibrate();
|
||||
//% weight=45
|
||||
void calibrateCompass() {
|
||||
uBit.compass.calibrate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,7 @@ namespace input {
|
||||
* @param body TODO
|
||||
*/
|
||||
//% help=input/on-screen-up
|
||||
export function onScreenUp(body: Action): void {
|
||||
export function onScreenUp(body: () => void): void {
|
||||
onGesture(Gesture.ScreenUp, body);
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ namespace input {
|
||||
* @param body TODO
|
||||
*/
|
||||
//% help=input/on-screen-down
|
||||
export function onScreenDown(body: Action): void {
|
||||
export function onScreenDown(body: () => void): void {
|
||||
onGesture(Gesture.ScreenDown, body);
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ namespace input {
|
||||
* @param body TODO
|
||||
*/
|
||||
//% help=input/on-shake
|
||||
export function onShake(body: Action): void {
|
||||
export function onShake(body: () => void): void {
|
||||
onGesture(Gesture.Shake, body);
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ namespace input {
|
||||
* @param body TODO
|
||||
*/
|
||||
//% help=input/on-logo-up
|
||||
export function onLogoUp(body: Action): void {
|
||||
export function onLogoUp(body: () => void): void {
|
||||
onGesture(Gesture.LogoUp, body);
|
||||
}
|
||||
|
||||
@ -44,7 +44,15 @@ namespace input {
|
||||
* @param body TODO
|
||||
*/
|
||||
//% help=input/on-logo-down
|
||||
export function onLogoDown(body: Action): void {
|
||||
export function onLogoDown(body: () => void): void {
|
||||
onGesture(Gesture.LogoDown, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obsolete, use input.calibrateCompass instead.
|
||||
*/
|
||||
//% weight=0 help=input/calibrate-compass
|
||||
export function calibrate() {
|
||||
input.calibrateCompass();
|
||||
}
|
||||
}
|
||||
|
BIN
libs/core/jres/gestures/backsideup-icon.png
Normal file
After Width: | Height: | Size: 699 B |
BIN
libs/core/jres/gestures/freefall-icon.png
Normal file
After Width: | Height: | Size: 1014 B |
BIN
libs/core/jres/gestures/frontsideup-icon.png
Normal file
After Width: | Height: | Size: 919 B |
BIN
libs/core/jres/gestures/impact3g-icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
libs/core/jres/gestures/impact6g-icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
libs/core/jres/gestures/impact8g-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/gestures/shake-icon.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
libs/core/jres/gestures/tiltforward-icon.png
Normal file
After Width: | Height: | Size: 808 B |
BIN
libs/core/jres/gestures/tiltleft-icon.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
libs/core/jres/gestures/tiltright-icon.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
libs/core/jres/icons/angry-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
libs/core/jres/icons/asleep-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/butterfly-icon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
libs/core/jres/icons/chessboard-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/confused-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/cow-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/diamond-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/duck-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/eigthnote-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/fabulous-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/ghost-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/giraffe-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/happy-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/heart-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/house-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
libs/core/jres/icons/lefttriangle-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/meh-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/no-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/pitchfork-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/quarternote-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/rabbit-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/rollerskate-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/sad-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/scissors-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/silly-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
libs/core/jres/icons/skull-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
libs/core/jres/icons/smalldiamond-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/smallheart-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/smallsquare-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/snake-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/square-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/stickfigure-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
libs/core/jres/icons/surprised-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/sword-icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
libs/core/jres/icons/target-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/tortoise-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
libs/core/jres/icons/triangle-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
libs/core/jres/icons/tshirt-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/umbrella-icon.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
libs/core/jres/icons/yes-icon.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
@ -2,6 +2,8 @@
|
||||
|
||||
enum class DisplayMode_ {
|
||||
//% block="black and white"
|
||||
BlackAndWhite = DISPLAY_MODE_BLACK_AND_WHITE,
|
||||
//% blockHidden=true
|
||||
BackAndWhite = DISPLAY_MODE_BLACK_AND_WHITE,
|
||||
//% block="greyscale"
|
||||
Greyscale = DISPLAY_MODE_GREYSCALE,
|
||||
@ -20,6 +22,7 @@ namespace led {
|
||||
//% blockId=device_plot block="plot|x %x|y %y" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1
|
||||
void plot(int x, int y) {
|
||||
uBit.display.image.setPixelValue(x, y, 0xff);
|
||||
}
|
||||
@ -34,6 +37,7 @@ namespace led {
|
||||
//% blockId=device_plot_brightness block="plot|x %x|y %y|brightness %brightness" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4 brightness.min=0 brightness.max=255
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1
|
||||
//% advanced=true
|
||||
void plotBrightness(int x, int y, int brightness) {
|
||||
brightness = max(0, min(0xff, brightness));
|
||||
@ -45,26 +49,28 @@ namespace led {
|
||||
|
||||
/**
|
||||
* Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param x the horizontal coordinate of the LED
|
||||
* @param y the vertical coordinate of the LED
|
||||
*/
|
||||
//% help=led/unplot weight=77
|
||||
//% blockId=device_unplot block="unplot|x %x|y %y" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1
|
||||
void unplot(int x, int y) {
|
||||
uBit.display.image.setPixelValue(x, y, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param x the horizontal coordinate of the LED
|
||||
* @param y the vertical coordinate of the LED
|
||||
*/
|
||||
//% help=led/point weight=76
|
||||
//% blockId=device_point block="point|x %x|y %y"
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1
|
||||
bool point(int x, int y) {
|
||||
int pix = uBit.display.image.getPixelValue(x, y);
|
||||
return pix > 0;
|
||||
@ -110,7 +116,8 @@ namespace led {
|
||||
* @param mode mode the display mode in which the screen operates
|
||||
*/
|
||||
//% weight=1 help=led/set-display-mode
|
||||
//% parts="ledmatrix" advanced=true
|
||||
//% parts="ledmatrix" advanced=true weight=1
|
||||
//% blockId="led_set_display_mode" block="set display mode $mode"
|
||||
void setDisplayMode(DisplayMode_ mode) {
|
||||
uBit.display.setDisplayMode((DisplayMode)mode);
|
||||
}
|
||||
@ -124,7 +131,7 @@ namespace led {
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on or off the display
|
||||
* Turns on or off the display
|
||||
*/
|
||||
//% help=led/enable blockId=device_led_enable block="led enable %on"
|
||||
//% advanced=true parts="ledmatrix"
|
||||
@ -139,7 +146,10 @@ namespace led {
|
||||
//% help=led/screenshot
|
||||
//% parts="ledmatrix"
|
||||
Image screenshot() {
|
||||
return uBit.display.screenShot().leakData();
|
||||
auto d = uBit.display.screenShot().leakData();
|
||||
auto r = NEW_GC(RefMImage, d);
|
||||
d->decr();
|
||||
return r;
|
||||
/*
|
||||
let Image img;
|
||||
img = image.createImage("");
|
||||
|
@ -16,22 +16,28 @@
|
||||
* @param high maximum value. If 0, maximum value adjusted automatically, eg: 0
|
||||
*/
|
||||
//% help=led/plot-bar-graph weight=20
|
||||
//% blockId=device_plot_bar_graph block="plot bar graph of %value |up to %high" icon="\uf080" blockExternalInputs=true
|
||||
//% blockId=device_plot_bar_graph block="plot bar graph of %value up to %high" icon="\uf080" blockExternalInputs=true
|
||||
//% parts="ledmatrix"
|
||||
export function plotBarGraph(value: number, high: number): void {
|
||||
let now = input.runningTime();
|
||||
serial.writeString(value.toString() + "\r\n");
|
||||
const now = input.runningTime();
|
||||
console.logValue("", value);
|
||||
value = Math.abs(value);
|
||||
|
||||
if (high != 0) barGraphHigh = high;
|
||||
else if (value > barGraphHigh || now - barGraphHighLast > 10000) {
|
||||
// auto-scale "high" is not provided
|
||||
if (high > 0) {
|
||||
barGraphHigh = high;
|
||||
} else if (value > barGraphHigh || now - barGraphHighLast > 10000) {
|
||||
barGraphHigh = value;
|
||||
barGraphHighLast = now;
|
||||
}
|
||||
|
||||
barGraphHigh = Math.max(barGraphHigh, 16);
|
||||
// normalize lack of data to 0..1
|
||||
if (barGraphHigh < 16 * Number.EPSILON)
|
||||
barGraphHigh = 1;
|
||||
|
||||
let v = (value * 15) / barGraphHigh;
|
||||
// normalize value to 0..1
|
||||
const v = value / barGraphHigh;
|
||||
const dv = 1 / 16;
|
||||
let k = 0;
|
||||
for (let y = 4; y >= 0; --y) {
|
||||
for (let x = 0; x < 3; ++x) {
|
||||
@ -42,19 +48,21 @@
|
||||
plot(2 - x, y);
|
||||
plot(2 + x, y);
|
||||
}
|
||||
++k;
|
||||
k += dv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles a particular pixel
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param x pixel column
|
||||
* @param y pixel row
|
||||
*/
|
||||
//% help=led/toggle weight=77
|
||||
//% blockId=device_led_toggle block="toggle|x %x|y %y" icon="\uf204" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1
|
||||
export function toggle(x: number, y: number): void {
|
||||
if (led.point(x, y)) {
|
||||
led.unplot(x, y);
|
||||
@ -91,7 +99,7 @@
|
||||
|
||||
/**
|
||||
* Fades in the screen display.
|
||||
* @param ms TODO
|
||||
* @param ms fade time in milleseconds
|
||||
*/
|
||||
//% help=led/fade-in
|
||||
//% parts="ledmatrix"
|
||||
@ -114,7 +122,7 @@
|
||||
|
||||
/**
|
||||
* Fades out the screen brightness.
|
||||
* @param ms TODO
|
||||
* @param ms fade time in milliseconds
|
||||
*/
|
||||
//% help=led/fade-out
|
||||
//% parts="ledmatrix"
|
||||
|
@ -17,4 +17,5 @@ namespace music {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -127,7 +127,7 @@ enum BeatFraction {
|
||||
}
|
||||
|
||||
enum MelodyOptions {
|
||||
//% block="once""
|
||||
//% block="once"
|
||||
Once = 1,
|
||||
//% block="forever"
|
||||
Forever = 2,
|
||||
@ -137,6 +137,15 @@ enum MelodyOptions {
|
||||
ForeverInBackground = 8
|
||||
}
|
||||
|
||||
enum MelodyStopOptions {
|
||||
//% block="all"
|
||||
All = MelodyOptions.Once | MelodyOptions.OnceInBackground,
|
||||
//% block="foreground"
|
||||
Foreground = MelodyOptions.Once,
|
||||
//% block="background"
|
||||
Background = MelodyOptions.OnceInBackground
|
||||
}
|
||||
|
||||
enum MusicEvent {
|
||||
//% block="melody note played"
|
||||
MelodyNotePlayed = 1,
|
||||
@ -166,13 +175,19 @@ enum MusicEvent {
|
||||
//% color=#DF4600 weight=98 icon="\uf025"
|
||||
namespace music {
|
||||
let beatsPerMinute: number = 120;
|
||||
let freqTable: number[] = [];
|
||||
//% whenUsed
|
||||
const freqs = hex`
|
||||
1f00210023002500270029002c002e003100340037003a003e004100450049004e00520057005c00620068006e00
|
||||
75007b0083008b0093009c00a500af00b900c400d000dc00e900f70006011501260137014a015d01720188019f01
|
||||
b801d201ee010b022a024b026e029302ba02e40210033f037003a403dc03170455049704dd0427057505c8052006
|
||||
7d06e0064907b8072d08a9082d09b9094d0aea0a900b400cfa0cc00d910e6f0f5a1053115b1272139a14d4152017
|
||||
8018f519801b231dde1e`;
|
||||
let _playTone: (frequency: number, duration: number) => void;
|
||||
const MICROBIT_MELODY_ID = 2000;
|
||||
|
||||
/**
|
||||
* Plays a tone through pin ``P0`` for the given duration.
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C
|
||||
* @param ms tone duration in milliseconds (ms)
|
||||
*/
|
||||
//% help=music/play-tone weight=90
|
||||
@ -186,7 +201,7 @@ namespace music {
|
||||
|
||||
/**
|
||||
* Plays a tone through pin ``P0``.
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz)
|
||||
* @param frequency pitch of the tone to play in Hertz (Hz), eg: Note.C
|
||||
*/
|
||||
//% help=music/ring-tone weight=80
|
||||
//% blockId=device_ring block="ring tone (Hz)|%note=device_note" blockGap=8
|
||||
@ -209,21 +224,24 @@ namespace music {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the frequency of a note.
|
||||
* Get the frequency of a note.
|
||||
* @param name the note name, eg: Note.C
|
||||
*/
|
||||
//% weight=50 help=music/note-frequency
|
||||
//% blockId=device_note block="%note"
|
||||
//% weight=1 help=music/note-frequency
|
||||
//% blockId=device_note block="%name"
|
||||
//% shim=TD_ID
|
||||
//% note.fieldEditor="note" note.defl="262"
|
||||
//% color="#FFFFFF" colorSecondary="#FFFFFF"
|
||||
//% name.fieldEditor="note" name.defl="262"
|
||||
//% name.fieldOptions.decompileLiterals=true
|
||||
//% useEnumVal=1
|
||||
//% weight=10 blockGap=8
|
||||
export function noteFrequency(name: Note): number {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
if (beatsPerMinute <= 0) beatsPerMinute = 120;
|
||||
if (freqTable.length == 0) freqTable = [31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, 65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 117, 123, 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 4186]
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,14 +252,14 @@ namespace music {
|
||||
export function beat(fraction?: BeatFraction): number {
|
||||
init();
|
||||
if (fraction == null) fraction = BeatFraction.Whole;
|
||||
let beat = 60000 / beatsPerMinute;
|
||||
let beat = Math.idiv(60000, beatsPerMinute);
|
||||
switch (fraction) {
|
||||
case BeatFraction.Half: return beat / 2;
|
||||
case BeatFraction.Quarter: return beat / 4;
|
||||
case BeatFraction.Eighth: return beat / 8;
|
||||
case BeatFraction.Sixteenth: return beat / 16;
|
||||
case BeatFraction.Double: return beat * 2;
|
||||
case BeatFraction.Breve: return beat * 4;
|
||||
case BeatFraction.Half: return beat >> 1;
|
||||
case BeatFraction.Quarter: return beat >> 2;
|
||||
case BeatFraction.Eighth: return beat >> 3;
|
||||
case BeatFraction.Sixteenth: return beat >> 4;
|
||||
case BeatFraction.Double: return beat << 1;
|
||||
case BeatFraction.Breve: return beat << 2;
|
||||
default: return beat;
|
||||
}
|
||||
}
|
||||
@ -299,18 +317,18 @@ namespace music {
|
||||
* Registers code to run on various melody events
|
||||
*/
|
||||
//% blockId=melody_on_event block="music on %value"
|
||||
//% help=music/on-event weight=59
|
||||
export function onEvent(value: MusicEvent, handler: Action) {
|
||||
//% help=music/on-event weight=59 blockGap=32
|
||||
export function onEvent(value: MusicEvent, handler: () => void) {
|
||||
control.onEvent(MICROBIT_MELODY_ID, value, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playing a melody.
|
||||
* Notes are expressed as a string of characters with this format: NOTE[octave][:duration]
|
||||
* @param melodyArray the melody array to play, eg: ['g5:1']
|
||||
* @param melodyArray the melody array to play
|
||||
* @param options melody options, once / forever, in the foreground / background
|
||||
*/
|
||||
//% help=music/begin-melody weight=60 blockGap=8
|
||||
//% help=music/begin-melody weight=60 blockGap=16
|
||||
//% blockId=device_start_melody block="start melody %melody=device_builtin_melody| repeating %options"
|
||||
//% parts="headphone"
|
||||
export function beginMelody(melodyArray: string[], options: MelodyOptions = 1) {
|
||||
@ -348,6 +366,20 @@ namespace music {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the melodies
|
||||
* @param options which melody to stop
|
||||
*/
|
||||
//% help=music/stop-melody weight=59 blockGap=16
|
||||
//% blockId=device_stop_melody block="stop melody $options"
|
||||
//% parts="headphone"
|
||||
export function stopMelody(options: MelodyStopOptions) {
|
||||
if (options & MelodyStopOptions.Background)
|
||||
beginMelody([], MelodyOptions.OnceInBackground);
|
||||
if (options & MelodyStopOptions.Foreground)
|
||||
beginMelody([], MelodyOptions.Once);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom playTone function for playing melodies
|
||||
*/
|
||||
@ -368,33 +400,34 @@ namespace music {
|
||||
let isrest: boolean = false;
|
||||
let beatPos: number;
|
||||
let parsingOctave: boolean = true;
|
||||
let prevNote: boolean = false;
|
||||
|
||||
for (let pos = 0; pos < currNote.length; pos++) {
|
||||
let noteChar = currNote.charAt(pos);
|
||||
switch (noteChar) {
|
||||
case 'c': case 'C': note = 1; break;
|
||||
case 'd': case 'D': note = 3; break;
|
||||
case 'e': case 'E': note = 5; break;
|
||||
case 'f': case 'F': note = 6; break;
|
||||
case 'g': case 'G': note = 8; break;
|
||||
case 'a': case 'A': note = 10; break;
|
||||
case 'b': case 'B': note = 12; break;
|
||||
case 'r': case 'R': isrest = true; break;
|
||||
case '#': note++; break;
|
||||
case 'b': note--; break;
|
||||
case ':': parsingOctave = false; beatPos = pos; break;
|
||||
default: if (parsingOctave) currentOctave = parseInt(noteChar);
|
||||
case 'c': case 'C': note = 1; prevNote = true; break;
|
||||
case 'd': case 'D': note = 3; prevNote = true; break;
|
||||
case 'e': case 'E': note = 5; prevNote = true; break;
|
||||
case 'f': case 'F': note = 6; prevNote = true; break;
|
||||
case 'g': case 'G': note = 8; prevNote = true; break;
|
||||
case 'a': case 'A': note = 10; prevNote = true; break;
|
||||
case 'B': note = 12; prevNote = true; break;
|
||||
case 'r': case 'R': isrest = true; prevNote = false; break;
|
||||
case '#': note++; prevNote = false; break;
|
||||
case 'b': if (prevNote) note--; else { note = 12; prevNote = true; } break;
|
||||
case ':': parsingOctave = false; beatPos = pos; prevNote = false; break;
|
||||
default: prevNote = false; if (parsingOctave) currentOctave = parseInt(noteChar);
|
||||
}
|
||||
}
|
||||
if (!parsingOctave) {
|
||||
currentDuration = parseInt(currNote.substr(beatPos + 1, currNote.length - beatPos));
|
||||
}
|
||||
let beat = (60000 / beatsPerMinute) / 4;
|
||||
let beat = Math.idiv(60000, beatsPerMinute) >> 2;
|
||||
if (isrest) {
|
||||
music.rest(currentDuration * beat)
|
||||
} else {
|
||||
let keyNumber = note + (12 * (currentOctave - 1));
|
||||
let frequency = keyNumber >= 0 && keyNumber < freqTable.length ? freqTable[keyNumber] : 0;
|
||||
let frequency = freqs.getNumber(NumberFormat.UInt16LE, keyNumber * 2) || 0;
|
||||
music.playTone(frequency, currentDuration * beat);
|
||||
}
|
||||
melody.currentDuration = currentDuration;
|
||||
|
@ -32,7 +32,9 @@ enum class AnalogPin {
|
||||
};
|
||||
|
||||
enum class PulseValue {
|
||||
//% block=high
|
||||
High = MICROBIT_PIN_EVT_PULSE_HI,
|
||||
//% block=low
|
||||
Low = MICROBIT_PIN_EVT_PULSE_LO
|
||||
};
|
||||
|
||||
@ -56,6 +58,9 @@ enum class PinEventType {
|
||||
None = MICROBIT_PIN_EVENT_NONE
|
||||
};
|
||||
|
||||
|
||||
namespace pxt
|
||||
{
|
||||
MicroBitPin *getPin(int id) {
|
||||
switch (id) {
|
||||
case MICROBIT_ID_IO_P0: return &uBit.io.P0;
|
||||
@ -82,6 +87,7 @@ MicroBitPin *getPin(int id) {
|
||||
}
|
||||
}
|
||||
|
||||
} // pxt
|
||||
|
||||
namespace pins {
|
||||
#define PINOP(op) \
|
||||
@ -133,7 +139,7 @@ namespace pins {
|
||||
//% help=pins/analog-read-pin weight=25
|
||||
//% blockId=device_get_analog_pin block="analog read|pin %name" blockGap="8"
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false"
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
|
||||
int analogReadPin(AnalogPin name) {
|
||||
PINREAD(getAnalogValue());
|
||||
}
|
||||
@ -147,13 +153,13 @@ namespace pins {
|
||||
//% blockId=device_set_analog_pin block="analog write|pin %name|to %value" blockGap=8
|
||||
//% value.min=0 value.max=1023
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false"
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
|
||||
void analogWritePin(AnalogPin name, int value) {
|
||||
PINOP(setAnalogValue(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.
|
||||
* Configure the pulse-width modulation (PWM) period of the analog output in microseconds.
|
||||
* If this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.
|
||||
* @param name analog pin to set period to, eg: AnalogPin.P0
|
||||
* @param micros period in micro seconds. eg:20000
|
||||
@ -167,11 +173,11 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``.
|
||||
* Configure the pin as a digital input and generate an event when the pin is pulsed either high or low.
|
||||
* @param name digital pin to register to, eg: DigitalPin.P0
|
||||
* @param pulse the value of the pulse, eg: PulseValue.High
|
||||
*/
|
||||
//% help=pins/on-pulsed weight=22 blockGap=8 advanced=true
|
||||
//% help=pins/on-pulsed weight=22 blockGap=16 advanced=true
|
||||
//% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse"
|
||||
//% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4
|
||||
//% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300"
|
||||
@ -184,7 +190,7 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler.
|
||||
* Get the duration of the last pulse in microseconds. This function should be called from a ``onPulsed`` handler.
|
||||
*/
|
||||
//% help=pins/pulse-duration advanced=true
|
||||
//% blockId=pins_pulse_duration block="pulse duration (µs)"
|
||||
@ -194,10 +200,10 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of a pulse in microseconds
|
||||
* Return the duration of a pulse at a pin in microseconds.
|
||||
* @param name the pin which measures the pulse, eg: DigitalPin.P0
|
||||
* @param value the value of the pulse, eg: PulseValue.High
|
||||
* @param maximum duration in micro-seconds
|
||||
* @param maximum duration in microseconds
|
||||
*/
|
||||
//% blockId="pins_pulse_in" block="pulse in (µs)|pin %name|pulsed %value"
|
||||
//% weight=20 advanced=true
|
||||
@ -237,7 +243,7 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
|
||||
* Write a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
|
||||
* @param name pin to write to, eg: AnalogPin.P0
|
||||
* @param value angle or rotation speed, eg:180,90,0
|
||||
*/
|
||||
@ -246,21 +252,21 @@ namespace pins {
|
||||
//% parts=microservo trackArgs=0
|
||||
//% value.min=0 value.max=180
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false"
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
|
||||
void servoWritePin(AnalogPin name, int value) {
|
||||
fixMotorIssue(name);
|
||||
PINOP(setServoValue(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.
|
||||
* Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds.
|
||||
* @param name pin name
|
||||
* @param micros pulse duration in micro seconds, eg:1500
|
||||
*/
|
||||
//% help=pins/servo-set-pulse weight=19
|
||||
//% blockId=device_set_servo_pulse block="servo set pulse|pin %value|to (µs) %micros"
|
||||
//% value.fieldEditor="gridpicker" value.fieldOptions.columns=4
|
||||
//% value.fieldOptions.tooltips="false"
|
||||
//% value.fieldOptions.tooltips="false" value.fieldOptions.width="250"
|
||||
void servoSetPulse(AnalogPin name, int micros) {
|
||||
fixMotorIssue(name);
|
||||
PINOP(setServoPulseUs(micros));
|
||||
@ -270,45 +276,45 @@ namespace pins {
|
||||
MicroBitPin* pitchPin = NULL;
|
||||
|
||||
/**
|
||||
* Sets the pin used when using `analog pitch` or music.
|
||||
* Set the pin used when using analog pitch or music.
|
||||
* @param name pin to modulate pitch from
|
||||
*/
|
||||
//% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name"
|
||||
//% help=pins/analog-set-pitch-pin weight=3 advanced=true
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false"
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250"
|
||||
void analogSetPitchPin(AnalogPin name) {
|
||||
pitchPin = getPin((int)name);
|
||||
}
|
||||
|
||||
pitchPin = getPin((int)name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.
|
||||
* @param frequency frequency to modulate in Hz.
|
||||
* @param ms duration of the pitch in milli seconds.
|
||||
*/
|
||||
* Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.
|
||||
* @param frequency frequency to modulate in Hz.
|
||||
* @param ms duration of the pitch in milli seconds.
|
||||
*/
|
||||
//% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms"
|
||||
//% help=pins/analog-pitch weight=4 async advanced=true blockGap=8
|
||||
void analogPitch(int frequency, int ms) {
|
||||
if (pitchPin == NULL)
|
||||
analogSetPitchPin(AnalogPin::P1);
|
||||
if (frequency <= 0) {
|
||||
pitchPin->setAnalogValue(0);
|
||||
} else {
|
||||
pitchPin->setAnalogValue(512);
|
||||
pitchPin->setAnalogPeriodUs(1000000/frequency);
|
||||
}
|
||||
|
||||
if (ms > 0) {
|
||||
fiber_sleep(ms);
|
||||
pitchPin->setAnalogValue(0);
|
||||
} else {
|
||||
pitchPin->setAnalogValue(512);
|
||||
pitchPin->setAnalogPeriodUs(1000000/frequency);
|
||||
}
|
||||
|
||||
if (ms > 0) {
|
||||
fiber_sleep(ms);
|
||||
pitchPin->setAnalogValue(0);
|
||||
// TODO why do we use wait_ms() here? it's a busy wait I think
|
||||
wait_ms(5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Configures the pull of this pin.
|
||||
* Configure the pull directiion of of a pin.
|
||||
* @param name pin to set the pull mode on, eg: DigitalPin.P0
|
||||
* @param pull one of the mbed pull configurations, eg: PinPullMode.PullUp
|
||||
*/
|
||||
@ -325,7 +331,7 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the events emitted by this pin. Events can be subscribed to
|
||||
* Configure the events emitted by this pin. Events can be subscribed to
|
||||
* using ``control.onEvent()``.
|
||||
* @param name pin to set the event mode on, eg: DigitalPin.P0
|
||||
* @param type the type of events for this pin to emit, eg: PinEventType.Edge
|
||||
@ -345,7 +351,7 @@ namespace pins {
|
||||
//%
|
||||
Buffer createBuffer(int size)
|
||||
{
|
||||
return ManagedBuffer(size).leakData();
|
||||
return mkBuffer(NULL, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,7 +361,7 @@ namespace pins {
|
||||
Buffer i2cReadBuffer(int address, int size, bool repeat = false)
|
||||
{
|
||||
Buffer buf = createBuffer(size);
|
||||
uBit.i2c.read(address << 1, (char*)buf->payload, size, repeat);
|
||||
uBit.i2c.read(address << 1, (char*)buf->data, size, repeat);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -363,11 +369,11 @@ namespace pins {
|
||||
* Write bytes to a 7-bit I2C `address`.
|
||||
*/
|
||||
//%
|
||||
void i2cWriteBuffer(int address, Buffer buf, bool repeat = false)
|
||||
int i2cWriteBuffer(int address, Buffer buf, bool repeat = false)
|
||||
{
|
||||
uBit.i2c.write(address << 1, (char*)buf->payload, buf->length, repeat);
|
||||
return uBit.i2c.write(address << 1, (char*)buf->data, buf->length, repeat);
|
||||
}
|
||||
|
||||
|
||||
SPI* spi = NULL;
|
||||
SPI* allocSPI() {
|
||||
if (NULL == spi)
|
||||
@ -387,7 +393,7 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SPI frequency
|
||||
* Set the SPI frequency
|
||||
* @param frequency the clock frequency, eg: 1000000
|
||||
*/
|
||||
//% help=pins/spi-frequency weight=4 advanced=true
|
||||
@ -398,7 +404,7 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SPI bits and mode
|
||||
* Set the SPI bits and mode
|
||||
* @param bits the number of bits, eg: 8
|
||||
* @param mode the mode, eg: 3
|
||||
*/
|
||||
@ -410,17 +416,17 @@ namespace pins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the MOSI, MISO, SCK pins used by the SPI instance
|
||||
* Set the MOSI, MISO, SCK pins used by the SPI connection
|
||||
*
|
||||
*/
|
||||
//% help=pins/spi-pins weight=2 advanced=true
|
||||
//% blockId=spi_pins block="spi set pins|MOSI %mosi|MISO %miso|SCK %sck"
|
||||
//% mosi.fieldEditor="gridpicker" mosi.fieldOptions.columns=4
|
||||
//% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="300"
|
||||
//% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="250"
|
||||
//% miso.fieldEditor="gridpicker" miso.fieldOptions.columns=4
|
||||
//% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="300"
|
||||
//% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="250"
|
||||
//% sck.fieldEditor="gridpicker" sck.fieldOptions.columns=4
|
||||
//% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="300"
|
||||
//% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="250"
|
||||
void spiPins(DigitalPin mosi, DigitalPin miso, DigitalPin sck) {
|
||||
if (NULL != spi) {
|
||||
delete spi;
|
||||
|
@ -5,7 +5,7 @@
|
||||
//% advanced=true
|
||||
namespace pins {
|
||||
/**
|
||||
* Re-maps a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.
|
||||
* Map a number from one range to another. That is, a value of ``from low`` would get mapped to ``to low``, a value of ``from high`` to ``to high``, values in-between to values in-between, etc.
|
||||
* @param value value to map in ranges
|
||||
* @param fromLow the lower bound of the value's current range
|
||||
* @param fromHigh the upper bound of the value's current range, eg: 1023
|
||||
@ -13,7 +13,7 @@ namespace pins {
|
||||
* @param toHigh the upper bound of the value's target range, eg: 4
|
||||
*/
|
||||
//% help=pins/map weight=23
|
||||
//% blockId=math_map block="map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh"
|
||||
//% blockId=pin_map block="map %value|from low %fromLow|from high %fromHigh|to low %toLow|to high %toHigh"
|
||||
export function map(value: number, fromLow: number, fromHigh: number, toLow: number, toHigh: number): number {
|
||||
return ((value - fromLow) * (toHigh - toLow)) / (fromHigh - fromLow) + toLow;
|
||||
}
|
||||
@ -21,50 +21,21 @@ namespace pins {
|
||||
/**
|
||||
* Read one number from 7-bit I2C address.
|
||||
*/
|
||||
//% help=pins/i2c-read-number blockGap=8
|
||||
//% blockId=pins_i2c_readnumber block="i2c read number|at address %address|of format %format=i2c_sizeof|repeat %repeat" weight=7
|
||||
export function i2cReadNumber(address: number, format: NumberFormat, repeat?: boolean): number {
|
||||
let buf = pins.i2cReadBuffer(address, pins.sizeOf(format), repeat)
|
||||
//% help=pins/i2c-read-number blockGap=8 advanced=true
|
||||
//% blockId=pins_i2c_readnumber block="i2c read number|at address %address|of format %format|repeated %repeat" weight=7
|
||||
export function i2cReadNumber(address: number, format: NumberFormat, repeated?: boolean): number {
|
||||
let buf = pins.i2cReadBuffer(address, pins.sizeOf(format), repeated)
|
||||
return buf.getNumber(format, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Write one number to a 7-bit I2C address.
|
||||
*/
|
||||
//% help=pins/i2c-write-number blockGap=8
|
||||
//% blockId=i2c_writenumber block="i2c write number|at address %address|with value %value|of format %format=i2c_sizeof|repeat %repeat" weight=6
|
||||
export function i2cWriteNumber(address: number, value: number, format: NumberFormat, repeat?: boolean): void {
|
||||
//% help=pins/i2c-write-number blockGap=8 advanced=true
|
||||
//% blockId=i2c_writenumber block="i2c write number|at address %address|with value %value|of format %format|repeated %repeat" weight=6
|
||||
export function i2cWriteNumber(address: number, value: number, format: NumberFormat, repeated?: boolean): void {
|
||||
let buf = createBuffer(pins.sizeOf(format))
|
||||
buf.setNumber(format, 0, value)
|
||||
pins.i2cWriteBuffer(address, buf, repeat)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size in bytes of specified number format.
|
||||
*/
|
||||
//%
|
||||
export function sizeOf(format: NumberFormat) {
|
||||
switch (format) {
|
||||
case NumberFormat.Int8LE:
|
||||
case NumberFormat.UInt8LE:
|
||||
case NumberFormat.Int8BE:
|
||||
case NumberFormat.UInt8BE:
|
||||
return 1;
|
||||
case NumberFormat.Int16LE:
|
||||
case NumberFormat.UInt16LE:
|
||||
case NumberFormat.Int16BE:
|
||||
case NumberFormat.UInt16BE:
|
||||
return 2;
|
||||
case NumberFormat.Int32LE:
|
||||
case NumberFormat.Int32BE:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
pins.i2cWriteBuffer(address, buf, repeated)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface Buffer {
|
||||
[index: number]: number;
|
||||
// rest defined in buffer.cpp
|
||||
}
|
||||
|
3
libs/core/platform.h
Normal file
@ -0,0 +1,3 @@
|
||||
// helpful define to handle C++ differences in package
|
||||
#define PXT_MICROBIT_TAGGED_INT 1
|
||||
#define PXT_POWI 1
|
@ -1,746 +0,0 @@
|
||||
#include "pxt.h"
|
||||
#include <map>
|
||||
|
||||
MicroBit uBit;
|
||||
|
||||
namespace pxt {
|
||||
int incr(uint32_t e)
|
||||
{
|
||||
if (e) {
|
||||
if (hasVTable(e))
|
||||
((RefObject*)e)->ref();
|
||||
else
|
||||
((RefCounted*)e)->incr();
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
void decr(uint32_t e)
|
||||
{
|
||||
if (e) {
|
||||
if (hasVTable(e))
|
||||
((RefObject*)e)->unref();
|
||||
else
|
||||
((RefCounted*)e)->decr();
|
||||
}
|
||||
}
|
||||
|
||||
Action mkAction(int reflen, int totallen, int startptr)
|
||||
{
|
||||
check(0 <= reflen && reflen <= totallen, ERR_SIZE, 1);
|
||||
check(reflen <= totallen && totallen <= 255, ERR_SIZE, 2);
|
||||
check(bytecode[startptr] == 0xffff, ERR_INVALID_BINARY_HEADER, 3);
|
||||
check(bytecode[startptr + 1] == 0, ERR_INVALID_BINARY_HEADER, 4);
|
||||
|
||||
uint32_t tmp = (uint32_t)&bytecode[startptr];
|
||||
|
||||
if (totallen == 0) {
|
||||
return tmp; // no closure needed
|
||||
}
|
||||
|
||||
void *ptr = ::operator new(sizeof(RefAction) + totallen * sizeof(uint32_t));
|
||||
RefAction *r = new (ptr) RefAction();
|
||||
r->len = totallen;
|
||||
r->reflen = reflen;
|
||||
r->func = (ActionCB)((tmp + 4) | 1);
|
||||
memset(r->fields, 0, r->len * sizeof(uint32_t));
|
||||
|
||||
return (Action)r;
|
||||
}
|
||||
|
||||
uint32_t runAction3(Action a, int arg0, int arg1, int arg2)
|
||||
{
|
||||
if (hasVTable(a))
|
||||
return ((RefAction*)a)->runCore(arg0, arg1, arg2);
|
||||
else {
|
||||
check(*(uint16_t*)a == 0xffff, ERR_INVALID_BINARY_HEADER, 4);
|
||||
return ((ActionCB)((a + 4) | 1))(NULL, arg0, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t runAction2(Action a, int arg0, int arg1)
|
||||
{
|
||||
return runAction3(a, arg0, arg1, 0);
|
||||
}
|
||||
|
||||
uint32_t runAction1(Action a, int arg0)
|
||||
{
|
||||
return runAction3(a, arg0, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t runAction0(Action a)
|
||||
{
|
||||
return runAction3(a, 0, 0, 0);
|
||||
}
|
||||
|
||||
RefRecord* mkClassInstance(int vtableOffset)
|
||||
{
|
||||
VTable *vtable = (VTable*)&bytecode[vtableOffset];
|
||||
|
||||
intcheck(vtable->methods[0] == &RefRecord_destroy, ERR_SIZE, 3);
|
||||
intcheck(vtable->methods[1] == &RefRecord_print, ERR_SIZE, 4);
|
||||
|
||||
void *ptr = ::operator new(vtable->numbytes);
|
||||
RefRecord *r = new (ptr) RefRecord(PXT_VTABLE_TO_INT(vtable));
|
||||
memset(r->fields, 0, vtable->numbytes - sizeof(RefRecord));
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t RefRecord::ld(int idx)
|
||||
{
|
||||
//intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 1);
|
||||
return fields[idx];
|
||||
}
|
||||
|
||||
uint32_t RefRecord::ldref(int idx)
|
||||
{
|
||||
//printf("LD %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx);
|
||||
//intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 2);
|
||||
uint32_t tmp = fields[idx];
|
||||
incr(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void RefRecord::st(int idx, uint32_t v)
|
||||
{
|
||||
//intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 3);
|
||||
fields[idx] = v;
|
||||
}
|
||||
|
||||
void RefRecord::stref(int idx, uint32_t v)
|
||||
{
|
||||
//printf("ST %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx);
|
||||
//intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 4);
|
||||
decr(fields[idx]);
|
||||
fields[idx] = v;
|
||||
}
|
||||
|
||||
void RefObject::destroy() {
|
||||
((RefObjectMethod)getVTable()->methods[0])(this);
|
||||
}
|
||||
|
||||
void RefObject::print() {
|
||||
((RefObjectMethod)getVTable()->methods[1])(this);
|
||||
}
|
||||
|
||||
void RefRecord_destroy(RefRecord *r) {
|
||||
auto tbl = r->getVTable();
|
||||
uint8_t *refmask = (uint8_t*)&tbl->methods[tbl->userdata & 0xff];
|
||||
int len = (tbl->numbytes >> 2) - 1;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (refmask[i]) decr(r->fields[i]);
|
||||
r->fields[i] = 0;
|
||||
}
|
||||
//RefRecord is allocated using placement new
|
||||
r->~RefRecord();
|
||||
::operator delete(r);
|
||||
}
|
||||
|
||||
void RefRecord_print(RefRecord *r)
|
||||
{
|
||||
printf("RefRecord %p r=%d size=%d bytes\n", r, r->refcnt, r->getVTable()->numbytes);
|
||||
}
|
||||
|
||||
uint32_t Segment::get(uint32_t i)
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("In Segment::get index:%u\n", i);
|
||||
this->print();
|
||||
#endif
|
||||
|
||||
if (i < length)
|
||||
{
|
||||
return data[i];
|
||||
}
|
||||
return Segment::DefaultValue;
|
||||
}
|
||||
|
||||
void Segment::set(uint32_t i, uint32_t value)
|
||||
{
|
||||
if (i < size)
|
||||
{
|
||||
data[i] = value;
|
||||
}
|
||||
else if (i < Segment::MaxSize)
|
||||
{
|
||||
growByMin(i + 1);
|
||||
data[i] = value;
|
||||
}
|
||||
if (length <= i)
|
||||
{
|
||||
length = i + 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("In Segment::set\n");
|
||||
this->print();
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t Segment::growthFactor(uint16_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if (size < 64)
|
||||
{
|
||||
return size * 2; // Double
|
||||
}
|
||||
if (size < 512)
|
||||
{
|
||||
return size * 5/3; //Grow by 1.66 rate
|
||||
}
|
||||
return size + 256; //Grow by constant rate
|
||||
}
|
||||
|
||||
void Segment::growByMin(uint16_t minSize)
|
||||
{
|
||||
growBy(max(minSize, growthFactor(size)));
|
||||
}
|
||||
|
||||
void Segment::growBy(uint16_t newSize)
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("growBy: %d\n", newSize);
|
||||
this->print();
|
||||
#endif
|
||||
if (size < newSize)
|
||||
{
|
||||
//this will throw if unable to allocate
|
||||
uint32_t *tmp = (uint32_t*)(::operator new(newSize * sizeof(uint32_t)));
|
||||
|
||||
//Copy existing data
|
||||
if (size)
|
||||
{
|
||||
memcpy(tmp, data, size * sizeof(uint32_t));
|
||||
}
|
||||
//fill the rest with default value
|
||||
memset(tmp + size, Segment::DefaultValue, (newSize - size) * sizeof(uint32_t));
|
||||
|
||||
//free older segment;
|
||||
::operator delete(data);
|
||||
|
||||
data = tmp;
|
||||
size = newSize;
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("growBy - after reallocation\n");
|
||||
this->print();
|
||||
#endif
|
||||
|
||||
}
|
||||
//else { no shrinking yet; }
|
||||
return;
|
||||
}
|
||||
|
||||
void Segment::ensure(uint16_t newSize)
|
||||
{
|
||||
if (newSize < size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
growByMin(newSize);
|
||||
}
|
||||
|
||||
void Segment::setLength(uint32_t newLength)
|
||||
{
|
||||
if (newLength > size)
|
||||
{
|
||||
ensure(length);
|
||||
}
|
||||
length = newLength;
|
||||
return;
|
||||
}
|
||||
|
||||
void Segment::push(uint32_t value)
|
||||
{
|
||||
this->set(length, value);
|
||||
}
|
||||
|
||||
uint32_t Segment::pop()
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("In Segment::pop\n");
|
||||
this->print();
|
||||
#endif
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
--length;
|
||||
uint32_t value = data[length];
|
||||
data[length] = Segment::DefaultValue;
|
||||
return value;
|
||||
}
|
||||
return Segment::DefaultValue;
|
||||
}
|
||||
|
||||
//this function removes an element at index i and shifts the rest of the elements to
|
||||
//left to fill the gap
|
||||
uint32_t Segment::remove(uint32_t i)
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("In Segment::remove index:%u\n", i);
|
||||
this->print();
|
||||
#endif
|
||||
if (i < length)
|
||||
{
|
||||
//value to return
|
||||
uint32_t ret = data[i];
|
||||
if (i + 1 < length)
|
||||
{
|
||||
//Move the rest of the elements to fill in the gap.
|
||||
memmove(data + i, data + i + 1, (length - i - 1) * sizeof(uint32_t));
|
||||
}
|
||||
length--;
|
||||
data[length] = Segment::DefaultValue;
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("After Segment::remove index:%u\n", i);
|
||||
this->print();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
return Segment::DefaultValue;
|
||||
}
|
||||
|
||||
//this function inserts element value at index i by shifting the rest of the elements right.
|
||||
void Segment::insert(uint32_t i, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("In Segment::insert index:%u value:%u\n", i, value);
|
||||
this->print();
|
||||
#endif
|
||||
|
||||
if (i < length)
|
||||
{
|
||||
ensure(length + 1);
|
||||
if (i + 1 < length)
|
||||
{
|
||||
//Move the rest of the elements to fill in the gap.
|
||||
memmove(data + i + 1, data + i, (length - i) * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
data[i] = value;
|
||||
length++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is insert beyond the length, just call set which will adjust the length
|
||||
set(i, value);
|
||||
}
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("After Segment::insert index:%u\n", i);
|
||||
this->print();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Segment::print()
|
||||
{
|
||||
printf("Segment: %x, length: %u, size: %u\n", data, (uint32_t)length, (uint32_t)size);
|
||||
for(uint32_t i = 0; i < size; i++)
|
||||
{
|
||||
printf("%d ",(uint32_t)data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
bool Segment::isValidIndex(uint32_t i)
|
||||
{
|
||||
if (i > length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Segment::destroy()
|
||||
{
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("In Segment::destroy\n");
|
||||
this->print();
|
||||
#endif
|
||||
length = size = 0;
|
||||
::operator delete(data);
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
void RefCollection::push(uint32_t x)
|
||||
{
|
||||
if (isRef()) incr(x);
|
||||
head.push(x);
|
||||
}
|
||||
|
||||
uint32_t RefCollection::pop()
|
||||
{
|
||||
uint32_t ret = head.pop();
|
||||
if (isRef())
|
||||
{
|
||||
incr(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t RefCollection::getAt(int i)
|
||||
{
|
||||
uint32_t tmp = head.get(i);
|
||||
if (isRef())
|
||||
{
|
||||
incr(tmp);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint32_t RefCollection::removeAt(int i)
|
||||
{
|
||||
// no decr() - we return the result
|
||||
return head.remove(i);
|
||||
}
|
||||
|
||||
void RefCollection::insertAt(int i, uint32_t value)
|
||||
{
|
||||
head.insert(i, value);
|
||||
if (isRef())
|
||||
{
|
||||
incr(value);
|
||||
}
|
||||
}
|
||||
|
||||
void RefCollection::setAt(int i, uint32_t value)
|
||||
{
|
||||
if (isRef())
|
||||
{
|
||||
if (head.isValidIndex((uint32_t)i))
|
||||
{
|
||||
decr(head.get(i));
|
||||
}
|
||||
incr(value);
|
||||
}
|
||||
head.set(i, value);
|
||||
}
|
||||
|
||||
int RefCollection::indexOf(uint32_t x, int start)
|
||||
{
|
||||
if (isString())
|
||||
{
|
||||
StringData *xx = (StringData*)x;
|
||||
uint32_t i = start;
|
||||
while(head.isValidIndex(i))
|
||||
{
|
||||
StringData *ee = (StringData*)head.get(i);
|
||||
if (ee == xx)
|
||||
{
|
||||
//handles ee being null
|
||||
return (int) i;
|
||||
}
|
||||
if (ee && xx->len == ee->len && memcmp(xx->data, ee->data, xx->len) == 0)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t i = start;
|
||||
while(head.isValidIndex(i))
|
||||
{
|
||||
if (head.get(i) == x)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RefCollection::removeElement(uint32_t x)
|
||||
{
|
||||
int idx = indexOf(x, 0);
|
||||
if (idx >= 0) {
|
||||
uint32_t elt = removeAt(idx);
|
||||
if (isRef()) decr(elt);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace Coll0 {
|
||||
PXT_VTABLE_BEGIN(RefCollection, 0, 0)
|
||||
PXT_VTABLE_END
|
||||
}
|
||||
namespace Coll1 {
|
||||
PXT_VTABLE_BEGIN(RefCollection, 1, 0)
|
||||
PXT_VTABLE_END
|
||||
}
|
||||
namespace Coll3 {
|
||||
PXT_VTABLE_BEGIN(RefCollection, 3, 0)
|
||||
PXT_VTABLE_END
|
||||
}
|
||||
|
||||
RefCollection::RefCollection(uint16_t flags) : RefObject(0) {
|
||||
switch (flags) {
|
||||
case 0:
|
||||
vtable = PXT_VTABLE_TO_INT(&Coll0::RefCollection_vtable);
|
||||
break;
|
||||
case 1:
|
||||
vtable = PXT_VTABLE_TO_INT(&Coll1::RefCollection_vtable);
|
||||
break;
|
||||
case 3:
|
||||
vtable = PXT_VTABLE_TO_INT(&Coll3::RefCollection_vtable);
|
||||
break;
|
||||
default:
|
||||
error(ERR_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RefCollection::destroy()
|
||||
{
|
||||
if (this->isRef())
|
||||
{
|
||||
for(uint32_t i = 0; i < this->head.getLength(); i++)
|
||||
{
|
||||
decr(this->head.get(i));
|
||||
}
|
||||
}
|
||||
this->head.destroy();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void RefCollection::print()
|
||||
{
|
||||
printf("RefCollection %p r=%d flags=%d size=%d\n", this, refcnt, getFlags(), head.getLength());
|
||||
head.print();
|
||||
}
|
||||
|
||||
PXT_VTABLE_CTOR(RefAction) {}
|
||||
|
||||
// fields[] contain captured locals
|
||||
void RefAction::destroy()
|
||||
{
|
||||
for (int i = 0; i < this->reflen; ++i) {
|
||||
decr(fields[i]);
|
||||
fields[i] = 0;
|
||||
}
|
||||
//RefAction is allocated using placement new
|
||||
this->~RefAction();
|
||||
::operator delete(this);
|
||||
}
|
||||
|
||||
void RefAction::print()
|
||||
{
|
||||
printf("RefAction %p r=%d pc=0x%lx size=%d (%d refs)\n", this, refcnt, (const uint8_t*)func - (const uint8_t*)bytecode, len, reflen);
|
||||
}
|
||||
|
||||
void RefLocal::print()
|
||||
{
|
||||
printf("RefLocal %p r=%d v=%d\n", this, refcnt, v);
|
||||
}
|
||||
|
||||
void RefLocal::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
PXT_VTABLE_CTOR(RefLocal) {
|
||||
v = 0;
|
||||
}
|
||||
|
||||
PXT_VTABLE_CTOR(RefRefLocal) {
|
||||
v = 0;
|
||||
}
|
||||
|
||||
void RefRefLocal::print()
|
||||
{
|
||||
printf("RefRefLocal %p r=%d v=%p\n", this, refcnt, (void*)v);
|
||||
}
|
||||
|
||||
void RefRefLocal::destroy()
|
||||
{
|
||||
decr(v);
|
||||
delete this;
|
||||
}
|
||||
|
||||
PXT_VTABLE_BEGIN(RefMap, 0, RefMapMarker)
|
||||
PXT_VTABLE_END
|
||||
RefMap::RefMap() : PXT_VTABLE_INIT(RefMap) {}
|
||||
|
||||
void RefMap::destroy() {
|
||||
for (unsigned i = 0; i < data.size(); ++i) {
|
||||
if (data[i].key & 1) {
|
||||
decr(data[i].val);
|
||||
}
|
||||
data[i].val = 0;
|
||||
}
|
||||
data.resize(0);
|
||||
delete this;
|
||||
}
|
||||
|
||||
int RefMap::findIdx(uint32_t key) {
|
||||
for (unsigned i = 0; i < data.size(); ++i) {
|
||||
if (data[i].key >> 1 == key)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void RefMap::print()
|
||||
{
|
||||
printf("RefMap %p r=%d size=%d\n", this, refcnt, data.size());
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_MEMLEAKS
|
||||
std::set<RefObject*> allptrs;
|
||||
void debugMemLeaks()
|
||||
{
|
||||
printf("LIVE POINTERS:\n");
|
||||
for(std::set<RefObject*>::iterator itr = allptrs.begin();itr!=allptrs.end();itr++)
|
||||
{
|
||||
(*itr)->print();
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#else
|
||||
void debugMemLeaks() {}
|
||||
#endif
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// An adapter for the API expected by the run-time.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
map<pair<int, int>, Action> handlersMap;
|
||||
|
||||
MicroBitEvent lastEvent;
|
||||
|
||||
// We have the invariant that if [dispatchEvent] is registered against the DAL
|
||||
// for a given event, then [handlersMap] contains a valid entry for that
|
||||
// event.
|
||||
void dispatchEvent(MicroBitEvent e) {
|
||||
|
||||
lastEvent = e;
|
||||
|
||||
Action curr = handlersMap[{ e.source, e.value }];
|
||||
if (curr)
|
||||
runAction1(curr, e.value);
|
||||
|
||||
curr = handlersMap[{ e.source, MICROBIT_EVT_ANY }];
|
||||
if (curr)
|
||||
runAction1(curr, e.value);
|
||||
}
|
||||
|
||||
void registerWithDal(int id, int event, Action a) {
|
||||
Action prev = handlersMap[{ id, event }];
|
||||
if (prev)
|
||||
decr(prev);
|
||||
else
|
||||
uBit.messageBus.listen(id, event, dispatchEvent);
|
||||
incr(a);
|
||||
handlersMap[{ id, event }] = a;
|
||||
}
|
||||
|
||||
void fiberDone(void *a)
|
||||
{
|
||||
decr((Action)a);
|
||||
release_fiber();
|
||||
}
|
||||
|
||||
|
||||
void runInBackground(Action a) {
|
||||
if (a != 0) {
|
||||
incr(a);
|
||||
create_fiber((void(*)(void*))runAction0, (void*)a, fiberDone);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void error(ERROR code, int subcode)
|
||||
{
|
||||
printf("Error: %d [%d]\n", code, subcode);
|
||||
uBit.panic(42);
|
||||
}
|
||||
|
||||
uint16_t *bytecode;
|
||||
uint32_t *globals;
|
||||
int numGlobals;
|
||||
|
||||
uint32_t *allocate(uint16_t sz)
|
||||
{
|
||||
uint32_t *arr = new uint32_t[sz];
|
||||
memset(arr, 0, sz * 4);
|
||||
return arr;
|
||||
}
|
||||
|
||||
void checkStr(bool cond, const char *msg)
|
||||
{
|
||||
if (!cond) {
|
||||
while (true) {
|
||||
uBit.display.scroll(msg, 100);
|
||||
uBit.sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int templateHash()
|
||||
{
|
||||
return ((int*)bytecode)[4];
|
||||
}
|
||||
|
||||
int programHash()
|
||||
{
|
||||
return ((int*)bytecode)[6];
|
||||
}
|
||||
|
||||
int getNumGlobals()
|
||||
{
|
||||
return bytecode[16];
|
||||
}
|
||||
|
||||
void exec_binary(int32_t *pc)
|
||||
{
|
||||
// XXX re-enable once the calibration code is fixed and [editor/embedded.ts]
|
||||
// properly prepends a call to [internal_main].
|
||||
// ::touch_develop::internal_main();
|
||||
|
||||
// unique group for radio based on source hash
|
||||
// ::touch_develop::micro_bit::radioDefaultGroup = programHash();
|
||||
|
||||
// repeat error 4 times and restart as needed
|
||||
microbit_panic_timeout(4);
|
||||
|
||||
int32_t ver = *pc++;
|
||||
checkStr(ver == 0x4209, ":( Bad runtime version");
|
||||
|
||||
bytecode = *((uint16_t**)pc++); // the actual bytecode is here
|
||||
globals = allocate(getNumGlobals());
|
||||
|
||||
// just compare the first word
|
||||
checkStr(((uint32_t*)bytecode)[0] == 0x923B8E70 &&
|
||||
templateHash() == *pc,
|
||||
":( Failed partial flash");
|
||||
|
||||
uint32_t startptr = (uint32_t)bytecode;
|
||||
startptr += 48; // header
|
||||
startptr |= 1; // Thumb state
|
||||
|
||||
((uint32_t (*)())startptr)();
|
||||
|
||||
#ifdef DEBUG_MEMLEAKS
|
||||
pxt::debugMemLeaks();
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
exec_binary((int32_t*)functionsAndBytecode);
|
||||
}
|
||||
}
|
||||
|
||||
// vim: ts=2 sw=2 expandtab
|
399
libs/core/pxt.h
@ -5,375 +5,70 @@
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "MicroBitImage.h"
|
||||
#include "ManagedString.h"
|
||||
#include "ManagedType.h"
|
||||
#include "ManagedBuffer.h"
|
||||
|
||||
#define printf(...) uBit.serial.printf(__VA_ARGS__)
|
||||
// #define printf(...)
|
||||
|
||||
#define intcheck(...) check(__VA_ARGS__)
|
||||
//#define intcheck(...) do {} while (0)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef DEBUG_MEMLEAKS
|
||||
#include <set>
|
||||
#endif
|
||||
|
||||
extern MicroBit uBit;
|
||||
#include "pxtbase.h"
|
||||
|
||||
namespace pxt {
|
||||
typedef uint32_t Action;
|
||||
typedef uint32_t ImageLiteral;
|
||||
|
||||
|
||||
typedef enum {
|
||||
ERR_INVALID_BINARY_HEADER = 5,
|
||||
ERR_OUT_OF_BOUNDS = 8,
|
||||
ERR_REF_DELETED = 7,
|
||||
ERR_SIZE = 9,
|
||||
} ERROR;
|
||||
|
||||
extern const uint32_t functionsAndBytecode[];
|
||||
extern uint32_t *globals;
|
||||
extern uint16_t *bytecode;
|
||||
class RefRecord;
|
||||
|
||||
// Utility functions
|
||||
extern MicroBitEvent lastEvent;
|
||||
void registerWithDal(int id, int event, Action a);
|
||||
void runInBackground(Action a);
|
||||
uint32_t runAction3(Action a, int arg0, int arg1, int arg2);
|
||||
uint32_t runAction2(Action a, int arg0, int arg1);
|
||||
uint32_t runAction1(Action a, int arg0);
|
||||
uint32_t runAction0(Action a);
|
||||
Action mkAction(int reflen, int totallen, int startptr);
|
||||
void error(ERROR code, int subcode = 0);
|
||||
void exec_binary(uint16_t *pc);
|
||||
void start();
|
||||
void debugMemLeaks();
|
||||
// allocate [sz] words and clear them
|
||||
uint32_t *allocate(uint16_t sz);
|
||||
int templateHash();
|
||||
int programHash();
|
||||
uint32_t programSize();
|
||||
uint32_t afterProgramPage();
|
||||
int getNumGlobals();
|
||||
RefRecord* mkClassInstance(int vtableOffset);
|
||||
|
||||
// The standard calling convention is:
|
||||
// - when a pointer is loaded from a local/global/field etc, and incr()ed
|
||||
// (in other words, its presence on stack counts as a reference)
|
||||
// - after a function call, all pointers are popped off the stack and decr()ed
|
||||
// This does not apply to the RefRecord and st/ld(ref) methods - they unref()
|
||||
// the RefRecord* this.
|
||||
int incr(uint32_t e);
|
||||
void decr(uint32_t e);
|
||||
|
||||
inline void *ptrOfLiteral(int offset)
|
||||
{
|
||||
return &bytecode[offset];
|
||||
}
|
||||
|
||||
inline ImageData* imageBytes(int offset)
|
||||
{
|
||||
return (ImageData*)(void*)&bytecode[offset];
|
||||
}
|
||||
|
||||
// Checks if object has a VTable, or if its RefCounted* from the runtime.
|
||||
inline bool hasVTable(uint32_t e)
|
||||
{
|
||||
return (*((uint32_t*)e) & 1) == 0;
|
||||
}
|
||||
|
||||
inline void check(int cond, ERROR code, int subcode = 0)
|
||||
{
|
||||
if (!cond) error(code, subcode);
|
||||
}
|
||||
|
||||
|
||||
class RefObject;
|
||||
#ifdef DEBUG_MEMLEAKS
|
||||
extern std::set<RefObject*> allptrs;
|
||||
#endif
|
||||
|
||||
typedef void (*RefObjectMethod)(RefObject *self);
|
||||
typedef void *PVoid;
|
||||
typedef void **PPVoid;
|
||||
|
||||
const PPVoid RefMapMarker = (PPVoid)(void*)43;
|
||||
|
||||
struct VTable {
|
||||
uint16_t numbytes; // in the entire object, including the vtable pointer
|
||||
uint16_t userdata;
|
||||
PVoid *ifaceTable;
|
||||
PVoid methods[2]; // we only use up to two methods here; pxt will generate more
|
||||
// refmask sits at &methods[nummethods]
|
||||
};
|
||||
|
||||
const int vtableShift = 2;
|
||||
|
||||
// A base abstract class for ref-counted objects.
|
||||
class RefObject
|
||||
{
|
||||
class RefMImage : public RefObject {
|
||||
public:
|
||||
uint16_t refcnt;
|
||||
uint16_t vtable;
|
||||
ImageData *img;
|
||||
|
||||
RefObject(uint16_t vt)
|
||||
{
|
||||
refcnt = 2;
|
||||
vtable = vt;
|
||||
#ifdef DEBUG_MEMLEAKS
|
||||
allptrs.insert(this);
|
||||
#endif
|
||||
}
|
||||
RefMImage(ImageData *d);
|
||||
void makeWritable();
|
||||
static void destroy(RefMImage *map);
|
||||
static void print(RefMImage *map);
|
||||
static void scan(RefMImage *t);
|
||||
static unsigned gcsize(RefMImage *t);
|
||||
};
|
||||
|
||||
inline VTable *getVTable() {
|
||||
return (VTable*)(vtable << vtableShift);
|
||||
}
|
||||
#define MSTR(s) ManagedString((s)->getUTF8Data(), (s)->getUTF8Size())
|
||||
|
||||
void destroy();
|
||||
void print();
|
||||
|
||||
// Call to disable pointer tracking on the current instance (in destructor or some other hack)
|
||||
inline void untrack() {
|
||||
#ifdef DEBUG_MEMLEAKS
|
||||
allptrs.erase(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Increment/decrement the ref-count. Decrementing to zero deletes the current object.
|
||||
inline void ref()
|
||||
{
|
||||
check(refcnt > 0, ERR_REF_DELETED);
|
||||
//printf("INCR "); this->print();
|
||||
refcnt += 2;
|
||||
}
|
||||
|
||||
inline void unref()
|
||||
{
|
||||
//printf("DECR "); this->print();
|
||||
check(refcnt > 0, ERR_REF_DELETED);
|
||||
refcnt -= 2;
|
||||
if (refcnt == 0) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Segment {
|
||||
private:
|
||||
uint32_t* data;
|
||||
uint16_t length;
|
||||
uint16_t size;
|
||||
|
||||
static const uint16_t MaxSize = 0xFFFF;
|
||||
static const uint32_t DefaultValue = 0x0;
|
||||
|
||||
static uint16_t growthFactor(uint16_t size);
|
||||
void growByMin(uint16_t minSize);
|
||||
void growBy(uint16_t newSize);
|
||||
void ensure(uint16_t newSize);
|
||||
|
||||
public:
|
||||
Segment() : data (nullptr), length(0), size(0) {};
|
||||
|
||||
uint32_t get(uint32_t i);
|
||||
void set(uint32_t i, uint32_t value);
|
||||
|
||||
uint32_t getLength() { return length;};
|
||||
void setLength(uint32_t newLength);
|
||||
|
||||
void push(uint32_t value);
|
||||
uint32_t pop();
|
||||
|
||||
uint32_t remove(uint32_t i);
|
||||
void insert(uint32_t i, uint32_t value);
|
||||
|
||||
bool isValidIndex(uint32_t i);
|
||||
|
||||
void destroy();
|
||||
|
||||
void print();
|
||||
};
|
||||
|
||||
// A ref-counted collection of either primitive or ref-counted objects (String, Image,
|
||||
// user-defined record, another collection)
|
||||
class RefCollection
|
||||
: public RefObject
|
||||
{
|
||||
private:
|
||||
Segment head;
|
||||
public:
|
||||
// 1 - collection of refs (need decr)
|
||||
// 2 - collection of strings (in fact we always have 3, never 2 alone)
|
||||
inline uint32_t getFlags() { return getVTable()->userdata; }
|
||||
inline bool isRef() { return getFlags() & 1; }
|
||||
inline bool isString() { return getFlags() & 2; }
|
||||
|
||||
RefCollection(uint16_t f);
|
||||
|
||||
void destroy();
|
||||
void print();
|
||||
|
||||
uint32_t length() { return head.getLength();}
|
||||
void setLength(uint32_t newLength) { head.setLength(newLength); }
|
||||
|
||||
void push(uint32_t x);
|
||||
uint32_t pop();
|
||||
uint32_t getAt(int i);
|
||||
void setAt(int i, uint32_t x);
|
||||
//removes the element at index i and shifts the other elements left
|
||||
uint32_t removeAt(int i);
|
||||
//inserts the element at index i and moves the other elements right.
|
||||
void insertAt(int i, uint32_t x);
|
||||
|
||||
int indexOf(uint32_t x, int start);
|
||||
int removeElement(uint32_t x);
|
||||
};
|
||||
|
||||
struct MapEntry {
|
||||
uint32_t key;
|
||||
uint32_t val;
|
||||
};
|
||||
|
||||
class RefMap
|
||||
: public RefObject
|
||||
{
|
||||
public:
|
||||
std::vector<MapEntry> data;
|
||||
|
||||
RefMap();
|
||||
void destroy();
|
||||
void print();
|
||||
int findIdx(uint32_t key);
|
||||
};
|
||||
|
||||
// A ref-counted, user-defined JS object.
|
||||
class RefRecord
|
||||
: public RefObject
|
||||
{
|
||||
public:
|
||||
// The object is allocated, so that there is space at the end for the fields.
|
||||
uint32_t fields[];
|
||||
|
||||
RefRecord(uint16_t v) : RefObject(v) {}
|
||||
|
||||
uint32_t ld(int idx);
|
||||
uint32_t ldref(int idx);
|
||||
void st(int idx, uint32_t v);
|
||||
void stref(int idx, uint32_t v);
|
||||
};
|
||||
|
||||
// these are needed when constructing vtables for user-defined classes
|
||||
void RefRecord_destroy(RefRecord *r);
|
||||
void RefRecord_print(RefRecord *r);
|
||||
|
||||
class RefAction;
|
||||
typedef uint32_t (*ActionCB)(uint32_t *captured, uint32_t arg0, uint32_t arg1, uint32_t arg2);
|
||||
|
||||
// Ref-counted function pointer. It's currently always a ()=>void procedure pointer.
|
||||
class RefAction
|
||||
: public RefObject
|
||||
{
|
||||
public:
|
||||
// This is the same as for RefRecord.
|
||||
uint8_t len;
|
||||
uint8_t reflen;
|
||||
ActionCB func; // The function pointer
|
||||
// fields[] contain captured locals
|
||||
uint32_t fields[];
|
||||
|
||||
void destroy();
|
||||
void print();
|
||||
|
||||
RefAction();
|
||||
|
||||
inline void stCore(int idx, uint32_t v)
|
||||
{
|
||||
//printf("ST [%d] = %d ", idx, v); this->print();
|
||||
intcheck(0 <= idx && idx < len, ERR_OUT_OF_BOUNDS, 10);
|
||||
intcheck(fields[idx] == 0, ERR_OUT_OF_BOUNDS, 11); // only one assignment permitted
|
||||
fields[idx] = v;
|
||||
}
|
||||
|
||||
inline uint32_t runCore(int arg0, int arg1, int arg2) // internal; use runAction*() functions
|
||||
{
|
||||
this->ref();
|
||||
uint32_t r = this->func(&this->fields[0], arg0, arg1, arg2);
|
||||
this->unref();
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
// These two are used to represent locals written from inside inline functions
|
||||
class RefLocal
|
||||
: public RefObject
|
||||
{
|
||||
public:
|
||||
uint32_t v;
|
||||
void destroy();
|
||||
void print();
|
||||
RefLocal();
|
||||
};
|
||||
|
||||
class RefRefLocal
|
||||
: public RefObject
|
||||
{
|
||||
public:
|
||||
uint32_t v;
|
||||
void destroy();
|
||||
void print();
|
||||
RefRefLocal();
|
||||
};
|
||||
static inline String PSTR(ManagedString s) {
|
||||
return mkString(s.toCharArray(), s.length());
|
||||
}
|
||||
|
||||
using namespace pxt;
|
||||
typedef uint32_t ImageLiteral_;
|
||||
|
||||
static inline ImageData *imageBytes(ImageLiteral_ lit) {
|
||||
return (ImageData *)lit;
|
||||
}
|
||||
|
||||
typedef RefMImage *Image;
|
||||
|
||||
extern MicroBit uBit;
|
||||
extern MicroBitEvent lastEvent;
|
||||
|
||||
MicroBitPin *getPin(int id);
|
||||
typedef ImageData* Image;
|
||||
typedef BufferData* Buffer;
|
||||
|
||||
// The ARM Thumb generator in the JavaScript code is parsing
|
||||
// the hex file and looks for the magic numbers as present here.
|
||||
//
|
||||
// Then it fetches function pointer addresses from there.
|
||||
|
||||
#define PXT_SHIMS_BEGIN \
|
||||
namespace pxt { \
|
||||
const uint32_t functionsAndBytecode[] __attribute__((aligned(0x20))) = { \
|
||||
0x08010801, 0x42424242, 0x08010801, 0x8de9d83e,
|
||||
static inline int min_(int a, int b) {
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
#define PXT_SHIMS_END }; }
|
||||
static inline int max_(int a, int b) {
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wpmf-conversions"
|
||||
void initMicrobitGC();
|
||||
|
||||
#define PXT_VTABLE_TO_INT(vt) ((uint32_t)(vt) >> vtableShift)
|
||||
#define PXT_VTABLE_BEGIN(classname, flags, iface) \
|
||||
const VTable classname ## _vtable \
|
||||
__attribute__((aligned(1 << vtableShift))) \
|
||||
= { \
|
||||
sizeof(classname), \
|
||||
flags, \
|
||||
iface, \
|
||||
{ \
|
||||
(void*)&classname::destroy, \
|
||||
(void*)&classname::print,
|
||||
} // namespace pxt
|
||||
|
||||
#define PXT_VTABLE_END } };
|
||||
using namespace pxt;
|
||||
|
||||
#define PXT_VTABLE_INIT(classname) \
|
||||
RefObject(PXT_VTABLE_TO_INT(&classname ## _vtable))
|
||||
#define DEVICE_EVT_ANY 0
|
||||
|
||||
#define PXT_VTABLE_CTOR(classname) \
|
||||
PXT_VTABLE_BEGIN(classname, 0, 0) PXT_VTABLE_END \
|
||||
classname::classname() : PXT_VTABLE_INIT(classname)
|
||||
#undef PXT_MAIN
|
||||
#define PXT_MAIN \
|
||||
int main() { \
|
||||
pxt::initMicrobitGC(); \
|
||||
pxt::start(); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,41 +1,54 @@
|
||||
{
|
||||
"name": "core",
|
||||
"description": "The microbit core library",
|
||||
"installedVersion": "tsmdvf",
|
||||
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/base",
|
||||
"files": [
|
||||
"README.md",
|
||||
"ManagedBuffer.cpp",
|
||||
"ManagedBuffer.h",
|
||||
"platform.h",
|
||||
"pxt.cpp",
|
||||
"pxt.h",
|
||||
"pxtbase.h",
|
||||
"pxtcore.h",
|
||||
"math.ts",
|
||||
"dal.d.ts",
|
||||
"enums.d.ts",
|
||||
"shims.d.ts",
|
||||
"pxt-core.d.ts",
|
||||
"pxt-core.d.ts",
|
||||
"core.cpp",
|
||||
"pxt-helpers.ts",
|
||||
"helpers.ts",
|
||||
"configkeys.h",
|
||||
"gc.cpp",
|
||||
"codal.cpp",
|
||||
"images.cpp",
|
||||
"basic.cpp",
|
||||
"basic.ts",
|
||||
"icons.ts",
|
||||
"icons.jres",
|
||||
"input.cpp",
|
||||
"input.ts",
|
||||
"gestures.jres",
|
||||
"control.ts",
|
||||
"control.cpp",
|
||||
"console.ts",
|
||||
"game.ts",
|
||||
"led.cpp",
|
||||
"led.ts",
|
||||
"motors.cpp",
|
||||
"music.cpp",
|
||||
"melodies.ts",
|
||||
"music.ts",
|
||||
"melodies.ts",
|
||||
"pins.cpp",
|
||||
"pins.ts",
|
||||
"serial.cpp",
|
||||
"serial.ts",
|
||||
"icons.ts",
|
||||
"buffer.cpp",
|
||||
"buffer.ts",
|
||||
"pxtparts.json",
|
||||
"advmath.cpp",
|
||||
"trig.cpp",
|
||||
"fixed.ts",
|
||||
"templates.ts",
|
||||
"parts/speaker.svg",
|
||||
"parts/headphone.svg",
|
||||
"parts/dcmotor.svg",
|
||||
@ -47,6 +60,7 @@
|
||||
"yotta": {
|
||||
"optionalConfig": {
|
||||
"microbit-dal": {
|
||||
"fiber_user_data": 1,
|
||||
"bluetooth": {
|
||||
"private_addressing": 0,
|
||||
"advertising_timeout": 0,
|
||||
@ -59,9 +73,48 @@
|
||||
"open": 0,
|
||||
"pairing_mode": 1,
|
||||
"whitelist": 1,
|
||||
"security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM"
|
||||
"security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM",
|
||||
"partial_flashing": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"userConfigs": [
|
||||
{
|
||||
"description": "No Pairing Required: Anyone can connect via Bluetooth.",
|
||||
"config": {
|
||||
"microbit-dal": {
|
||||
"bluetooth": {
|
||||
"open": 1,
|
||||
"whitelist": 0,
|
||||
"security_level": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "JustWorks pairing (default): Pairing is automatic once the pairing is initiated.",
|
||||
"config": {
|
||||
"microbit-dal": {
|
||||
"bluetooth": {
|
||||
"open": 0,
|
||||
"whitelist": 1,
|
||||
"security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Passkey pairing: Pairing requires 6 digit key to pair.",
|
||||
"config": {
|
||||
"microbit-dal": {
|
||||
"bluetooth": {
|
||||
"open": 0,
|
||||
"whitelist": 1,
|
||||
"security_level": "SECURITY_MODE_ENCRYPTION_WITH_MITM"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
24
libs/core/pxtcore.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef __PXTCORE_H
|
||||
#define __PXTCORE_H
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "MicroBitImage.h"
|
||||
#include "ManagedString.h"
|
||||
#include "ManagedType.h"
|
||||
|
||||
namespace pxt {
|
||||
void debuglog(const char *format, ...);
|
||||
}
|
||||
|
||||
// #define GC_GET_HEAP_SIZE() device_heap_size(0)
|
||||
#define xmalloc malloc
|
||||
#define xfree free
|
||||
|
||||
#define GC_MAX_ALLOC_SIZE 9000
|
||||
|
||||
#define GC_BLOCK_SIZE 256
|
||||
#define NON_GC_HEAP_RESERVATION 1024
|
||||
|
||||
#define DMESG NOLOG
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"buttonpair": {
|
||||
{
|
||||
"buttonpair": {
|
||||
"simulationBehavior": "buttonpair",
|
||||
"visual": {
|
||||
"builtIn": "buttonpair",
|
||||
@ -7,26 +7,66 @@
|
||||
"height": 45,
|
||||
"pinDistance": 15,
|
||||
"pinLocations": [
|
||||
{"x": 0, "y": 0},
|
||||
{"x": 30, "y": 45},
|
||||
{"x": 45, "y": 0},
|
||||
{"x": 75, "y": 45}
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 30,
|
||||
"y": 45
|
||||
},
|
||||
{
|
||||
"x": 45,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 75,
|
||||
"y": 45
|
||||
}
|
||||
]
|
||||
},
|
||||
"numberOfPins": 4,
|
||||
"pinDefinitions": [
|
||||
{"target": "P14", "style": "male", "orientation": "-Z"},
|
||||
{"target": "ground", "style": "male", "orientation": "-Z"},
|
||||
{"target": "P15", "style": "male", "orientation": "-Z"},
|
||||
{"target": "ground", "style": "male", "orientation": "-Z"}
|
||||
{
|
||||
"target": "P14",
|
||||
"style": "male",
|
||||
"orientation": "-Z"
|
||||
},
|
||||
{
|
||||
"target": "ground",
|
||||
"style": "male",
|
||||
"orientation": "-Z"
|
||||
},
|
||||
{
|
||||
"target": "P15",
|
||||
"style": "male",
|
||||
"orientation": "-Z"
|
||||
},
|
||||
{
|
||||
"target": "ground",
|
||||
"style": "male",
|
||||
"orientation": "-Z"
|
||||
}
|
||||
],
|
||||
"instantiation": {
|
||||
"kind": "singleton"
|
||||
},
|
||||
"assembly": [
|
||||
{"part": true},
|
||||
{"pinIndices": [0, 1]},
|
||||
{"pinIndices": [2, 3]}
|
||||
{
|
||||
"part": true
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"microservo": {
|
||||
@ -37,27 +77,65 @@
|
||||
"height": 200,
|
||||
"pinDistance": 10,
|
||||
"pinLocations": [
|
||||
{"x": 30, "y": 5},
|
||||
{"x": 37, "y": 5},
|
||||
{"x": 45, "y": 5}
|
||||
{
|
||||
"x": 30,
|
||||
"y": 5
|
||||
},
|
||||
{
|
||||
"x": 37,
|
||||
"y": 5
|
||||
},
|
||||
{
|
||||
"x": 45,
|
||||
"y": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"numberOfPins": 3,
|
||||
"pinDefinitions": [
|
||||
{"target": {"pinInstantiationIdx": 0}, "style": "croc", "orientation": "+Z"},
|
||||
{"target": "threeVolt", "style": "croc", "orientation": "+Z"},
|
||||
{"target": "ground", "style": "croc", "orientation": "+Z"}
|
||||
{
|
||||
"target": {
|
||||
"pinInstantiationIdx": 0
|
||||
},
|
||||
"style": "croc",
|
||||
"orientation": "+Z"
|
||||
},
|
||||
{
|
||||
"target": "threeVolt",
|
||||
"style": "croc",
|
||||
"orientation": "+Z"
|
||||
},
|
||||
{
|
||||
"target": "ground",
|
||||
"style": "croc",
|
||||
"orientation": "+Z"
|
||||
}
|
||||
],
|
||||
"instantiations": [
|
||||
{
|
||||
"kind": "function",
|
||||
"fullyQualifiedName": "pins.servoWritePin,pins.servoSetPulse,PwmOnlyPin.servoWrite,PwmOnlyPin.servoSetPulse,servos.Servo.setAngle,servos.Servo.run,servos.Servo.setPulse",
|
||||
"argumentRoles": [
|
||||
{
|
||||
"pinInstantiationIdx": 0,
|
||||
"partParameter": "name"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"instantiation": {
|
||||
"kind": "function",
|
||||
"fullyQualifiedName": "pins.servoWritePin",
|
||||
"argumentRoles": [
|
||||
{"pinInstantiationIdx": 0, "partParameter": "name"}
|
||||
]
|
||||
},
|
||||
"assembly": [
|
||||
{"part": true, "pinIndices": [2]},
|
||||
{"pinIndices": [0, 1]}
|
||||
{
|
||||
"part": true,
|
||||
"pinIndices": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"neopixel": {
|
||||
@ -68,28 +146,66 @@
|
||||
"height": 113,
|
||||
"pinDistance": 9,
|
||||
"pinLocations": [
|
||||
{"x": 10, "y": 0},
|
||||
{"x": 19, "y": 0},
|
||||
{"x": 28, "y": 0}
|
||||
{
|
||||
"x": 10,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 19,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 28,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"numberOfPins": 3,
|
||||
"pinDefinitions": [
|
||||
{"target": {"pinInstantiationIdx": 0}, "style": "solder", "orientation": "+Z"},
|
||||
{"target": "threeVolt", "style": "solder", "orientation": "+Z"},
|
||||
{"target": "ground", "style": "solder", "orientation": "+Z"}
|
||||
{
|
||||
"target": {
|
||||
"pinInstantiationIdx": 0
|
||||
},
|
||||
"style": "solder",
|
||||
"orientation": "+Z"
|
||||
},
|
||||
{
|
||||
"target": "threeVolt",
|
||||
"style": "solder",
|
||||
"orientation": "+Z"
|
||||
},
|
||||
{
|
||||
"target": "ground",
|
||||
"style": "solder",
|
||||
"orientation": "+Z"
|
||||
}
|
||||
],
|
||||
"instantiation": {
|
||||
"kind": "function",
|
||||
"fullyQualifiedName": "neopixel.create",
|
||||
"argumentRoles": [
|
||||
{"pinInstantiationIdx": 0, "partParameter": "pin"},
|
||||
{"partParameter": "mode"}
|
||||
{
|
||||
"pinInstantiationIdx": 0,
|
||||
"partParameter": "pin"
|
||||
},
|
||||
{
|
||||
"partParameter": "mode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assembly": [
|
||||
{"part": true, "pinIndices": [2]},
|
||||
{"pinIndices": [0, 1]}
|
||||
{
|
||||
"part": true,
|
||||
"pinIndices": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ledmatrix": {
|
||||
@ -99,37 +215,137 @@
|
||||
"height": 105,
|
||||
"pinDistance": 15,
|
||||
"pinLocations": [
|
||||
{"x": 0, "y": 0},
|
||||
{"x": 15, "y": 0},
|
||||
{"x": 30, "y": 0},
|
||||
{"x": 45, "y": 0},
|
||||
{"x": 105, "y": 105},
|
||||
{"x": 0, "y": 105},
|
||||
{"x": 15, "y": 105},
|
||||
{"x": 30, "y": 105},
|
||||
{"x": 45, "y": 105},
|
||||
{"x": 60, "y": 0}
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 15,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 30,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 45,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 105,
|
||||
"y": 105
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 105
|
||||
},
|
||||
{
|
||||
"x": 15,
|
||||
"y": 105
|
||||
},
|
||||
{
|
||||
"x": 30,
|
||||
"y": 105
|
||||
},
|
||||
{
|
||||
"x": 45,
|
||||
"y": 105
|
||||
},
|
||||
{
|
||||
"x": 60,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"simulationBehavior": "ledmatrix",
|
||||
"numberOfPins": 10,
|
||||
"instantiation": {"kind": "singleton"},
|
||||
"instantiation": {
|
||||
"kind": "singleton"
|
||||
},
|
||||
"pinDefinitions": [
|
||||
{"target": "P6", "style": "male", "orientation": "-Z", "colorGroup": 0},
|
||||
{"target": "P7", "style": "male", "orientation": "-Z", "colorGroup": 0},
|
||||
{"target": "P8", "style": "male", "orientation": "-Z", "colorGroup": 0},
|
||||
{"target": "P9", "style": "male", "orientation": "-Z", "colorGroup": 0},
|
||||
{"target": "P10", "style": "male", "orientation": "-Z", "colorGroup": 0},
|
||||
{"target": "P12", "style": "male", "orientation": "-Z", "colorGroup": 1},
|
||||
{"target": "P13", "style": "male", "orientation": "-Z", "colorGroup": 1},
|
||||
{"target": "P16", "style": "male", "orientation": "-Z", "colorGroup": 1},
|
||||
{"target": "P19", "style": "male", "orientation": "-Z", "colorGroup": 1},
|
||||
{"target": "P20", "style": "male", "orientation": "-Z", "colorGroup": 1}
|
||||
{
|
||||
"target": "P6",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 0
|
||||
},
|
||||
{
|
||||
"target": "P7",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 0
|
||||
},
|
||||
{
|
||||
"target": "P8",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 0
|
||||
},
|
||||
{
|
||||
"target": "P9",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 0
|
||||
},
|
||||
{
|
||||
"target": "P10",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 0
|
||||
},
|
||||
{
|
||||
"target": "P12",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 1
|
||||
},
|
||||
{
|
||||
"target": "P13",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 1
|
||||
},
|
||||
{
|
||||
"target": "P16",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 1
|
||||
},
|
||||
{
|
||||
"target": "P19",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 1
|
||||
},
|
||||
{
|
||||
"target": "P20",
|
||||
"style": "male",
|
||||
"orientation": "-Z",
|
||||
"colorGroup": 1
|
||||
}
|
||||
],
|
||||
"assembly": [
|
||||
{"part": true},
|
||||
{"pinIndices": [0, 1, 2, 3, 4]},
|
||||
{"pinIndices": [5, 6, 7, 8, 9]}
|
||||
{
|
||||
"part": true
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"headphone": {
|
||||
@ -140,18 +356,43 @@
|
||||
"height": 180,
|
||||
"pinDistance": 20,
|
||||
"pinLocations": [
|
||||
{"x": 17, "y": 11},
|
||||
{"x": 55, "y": 50}
|
||||
{
|
||||
"x": 17,
|
||||
"y": 11
|
||||
},
|
||||
{
|
||||
"x": 55,
|
||||
"y": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
"pinDefinitions": [
|
||||
{"target": "P0", "style": "croc", "orientation": "Y"},
|
||||
{"target": "ground", "style": "croc", "orientation": "Y"}
|
||||
{
|
||||
"target": "P0",
|
||||
"style": "croc",
|
||||
"orientation": "Y"
|
||||
},
|
||||
{
|
||||
"target": "ground",
|
||||
"style": "croc",
|
||||
"orientation": "Y"
|
||||
}
|
||||
],
|
||||
"instantiation": {"kind": "singleton"},
|
||||
"instantiation": {
|
||||
"kind": "singleton"
|
||||
},
|
||||
"assembly": [
|
||||
{"part": true, "pinIndices": [0]},
|
||||
{"pinIndices": [1]}
|
||||
{
|
||||
"part": true,
|
||||
"pinIndices": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"speaker": {
|
||||
@ -162,39 +403,43 @@
|
||||
"height": 500,
|
||||
"pinDistance": 70,
|
||||
"pinLocations": [
|
||||
{"x": 180, "y": 135},
|
||||
{"x": 320, "y": 135}
|
||||
{
|
||||
"x": 180,
|
||||
"y": 135
|
||||
},
|
||||
{
|
||||
"x": 320,
|
||||
"y": 135
|
||||
}
|
||||
]
|
||||
},
|
||||
"pinDefinitions": [
|
||||
{"target": "P0", "style": "male", "orientation": "-Z"},
|
||||
{"target": "ground", "style": "male", "orientation": "-Z"}
|
||||
{
|
||||
"target": "P0",
|
||||
"style": "male",
|
||||
"orientation": "-Z"
|
||||
},
|
||||
{
|
||||
"target": "ground",
|
||||
"style": "male",
|
||||
"orientation": "-Z"
|
||||
}
|
||||
],
|
||||
"instantiation": {"kind": "singleton"},
|
||||
"assembly": [
|
||||
{"part": true, "pinIndices": [0]},
|
||||
{"pinIndices": [1]}
|
||||
]
|
||||
},
|
||||
"dcmotor": {
|
||||
"numberOfPins": 2,
|
||||
"visual": {
|
||||
"image": "parts/dcmotor.svg",
|
||||
"width": 488,
|
||||
"height": 836,
|
||||
"pinDistance": 65,
|
||||
"pinLocations": [
|
||||
{"x": 89, "y": 48},
|
||||
{"x": 393, "y": 48} ]
|
||||
"instantiation": {
|
||||
"kind": "singleton"
|
||||
},
|
||||
"pinDefinitions": [
|
||||
{ "target": "M_OUT1", "style": "croc", "orientation": "-Z"},
|
||||
{ "target": "M_OUT2", "style": "croc", "orientation": "-Z"}
|
||||
],
|
||||
"instantiation": {"kind": "singleton"},
|
||||
"assembly": [
|
||||
{"part": true, "pinIndices": [0]},
|
||||
{"pinIndices": [1]}
|
||||
{
|
||||
"part": true,
|
||||
"pinIndices": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"pinIndices": [
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,45 @@
|
||||
#include "pxt.h"
|
||||
|
||||
#define MICROBIT_SERIAL_READ_BUFFER_LENGTH 64
|
||||
|
||||
// make sure USB_TX and USB_RX don't overlap with other pin ids
|
||||
enum SerialPin {
|
||||
C16 = MICROBIT_ID_IO_P2,
|
||||
C17 = MICROBIT_ID_IO_P8,
|
||||
P0 = MICROBIT_ID_IO_P12,
|
||||
P1 = MICROBIT_ID_IO_P0,
|
||||
P2 = MICROBIT_ID_IO_P1,
|
||||
P3 = MICROBIT_ID_IO_P16,
|
||||
P0 = MICROBIT_ID_IO_P0,
|
||||
P1 = MICROBIT_ID_IO_P1,
|
||||
P2 = MICROBIT_ID_IO_P2,
|
||||
P8 = MICROBIT_ID_IO_P8,
|
||||
P12 = MICROBIT_ID_IO_P12,
|
||||
P13 = MICROBIT_ID_IO_P13,
|
||||
P14 = MICROBIT_ID_IO_P14,
|
||||
P15 = MICROBIT_ID_IO_P15,
|
||||
P16 = MICROBIT_ID_IO_P16,
|
||||
USB_TX = 1001,
|
||||
USB_RX = 1002
|
||||
};
|
||||
|
||||
enum BaudRate {
|
||||
//% block=115200
|
||||
BaudRate115200 = 115200,
|
||||
//% block=57600
|
||||
BaudRate56700 = 57600,
|
||||
BaudRate57600 = 57600,
|
||||
//% block=38400
|
||||
BaudRate38400 = 38400,
|
||||
//% block=31250
|
||||
BaudRate31250 = 31250,
|
||||
//% block=28800
|
||||
BaudRate28800 = 28800,
|
||||
//% block=19200
|
||||
BaudRate19200 = 19200,
|
||||
//% block=14400
|
||||
BaudRate14400 = 14400,
|
||||
//% block=9600
|
||||
BaudRate9600 = 9600
|
||||
BaudRate9600 = 9600,
|
||||
//% block=4800
|
||||
BaudRate4800 = 4800,
|
||||
//% block=2400
|
||||
BaudRate2400 = 2400,
|
||||
//% block=1200
|
||||
BaudRate1200 = 1200
|
||||
};
|
||||
|
||||
enum Delimiters {
|
||||
@ -33,71 +57,158 @@ enum Delimiters {
|
||||
Hash = 6,
|
||||
};
|
||||
|
||||
//% weight=2 color=30
|
||||
//% weight=2 color=#002050 icon="\uf287"
|
||||
//% advanced=true
|
||||
namespace serial {
|
||||
// note that at least one // followed by % is needed per declaration!
|
||||
|
||||
/**
|
||||
* Reads a line of text from the serial port and returns the buffer when the delimiter is met.
|
||||
* Read a line of text from the serial port and return the buffer when the delimiter is met.
|
||||
* @param delimiter text delimiter that separates each text chunk
|
||||
*/
|
||||
//% help=serial/read-until
|
||||
//% blockId=serial_read_until block="serial|read until %delimiter=serial_delimiter_conv"
|
||||
//% weight=19
|
||||
StringData* readUntil(StringData* delimiter) {
|
||||
return uBit.serial.readUntil(ManagedString(delimiter)).leakData();
|
||||
String readUntil(String delimiter) {
|
||||
return PSTR(uBit.serial.readUntil(MSTR(delimiter)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the buffered received data as a string
|
||||
* Read the buffered received data as a string
|
||||
*/
|
||||
//% help=serial/read-string
|
||||
//% blockId=serial_read_buffer block="serial|read string"
|
||||
//% weight=18
|
||||
StringData* readString() {
|
||||
String readString() {
|
||||
int n = uBit.serial.getRxBufferSize();
|
||||
if (n == 0) return ManagedString("").leakData();
|
||||
return ManagedString(uBit.serial.read(n, MicroBitSerialMode::ASYNC)).leakData();
|
||||
if (n == 0) return mkString("", 0);
|
||||
return PSTR(uBit.serial.read(n, MicroBitSerialMode::ASYNC));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an event to be fired when one of the delimiter is matched.
|
||||
* Register an event to be fired when one of the delimiter is matched.
|
||||
* @param delimiters the characters to match received characters against.
|
||||
*/
|
||||
//% help=serial/on-data-received
|
||||
//% weight=18 blockId=serial_on_data_received block="serial|on data received %delimiters=serial_delimiter_conv"
|
||||
void onDataReceived(StringData* delimiters, Action body) {
|
||||
uBit.serial.eventOn(ManagedString(delimiters));
|
||||
void onDataReceived(String delimiters, Action body) {
|
||||
uBit.serial.eventOn(MSTR(delimiters));
|
||||
registerWithDal(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_DELIM_MATCH, body);
|
||||
// lazy initialization of serial buffers
|
||||
uBit.serial.read(MicroBitSerialMode::ASYNC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a piece of text through Serial connection.
|
||||
* Send a piece of text through the serial connection.
|
||||
*/
|
||||
//% help=serial/write-string
|
||||
//% weight=87
|
||||
//% weight=87 blockGap=8
|
||||
//% blockId=serial_writestring block="serial|write string %text"
|
||||
void writeString(StringData *text) {
|
||||
uBit.serial.send(ManagedString(text));
|
||||
//% text.shadowOptions.toString=true
|
||||
void writeString(String text) {
|
||||
if (!text) return;
|
||||
|
||||
uBit.serial.send(MSTR(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically configuring the serial instance to use pins other than USBTX and USBRX.
|
||||
* @param tx the new transmission pins, eg: SerialPin.P0
|
||||
* Send a buffer through serial connection
|
||||
*/
|
||||
//% blockId=serial_writebuffer block="serial|write buffer %buffer=serial_readbuffer"
|
||||
//% help=serial/write-buffer advanced=true weight=6
|
||||
void writeBuffer(Buffer buffer) {
|
||||
if (!buffer) return;
|
||||
|
||||
uBit.serial.send(buffer->data, buffer->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read multiple characters from the receive buffer. Pause until enough characters are present.
|
||||
* @param length default buffer length, eg: 64
|
||||
*/
|
||||
//% blockId=serial_readbuffer block="serial|read buffer %length"
|
||||
//% help=serial/read-buffer advanced=true weight=5
|
||||
Buffer readBuffer(int length) {
|
||||
if (length <= 0)
|
||||
length = MICROBIT_SERIAL_READ_BUFFER_LENGTH;
|
||||
|
||||
auto buf = mkBuffer(NULL, length);
|
||||
int read = uBit.serial.read(buf->data, buf->length);
|
||||
if (read != length) {
|
||||
auto prev = buf;
|
||||
buf = mkBuffer(buf->data, read);
|
||||
decrRC(prev);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool tryResolvePin(SerialPin p, PinName& name) {
|
||||
switch(p) {
|
||||
case SerialPin::USB_TX: name = USBTX; return true;
|
||||
case SerialPin::USB_RX: name = USBRX; return true;
|
||||
default:
|
||||
auto pin = getPin(p);
|
||||
if (NULL != pin) {
|
||||
name = pin->name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the serial input and output to use pins instead of the USB connection.
|
||||
* @param tx the new transmission pin, eg: SerialPin.P0
|
||||
* @param rx the new reception pin, eg: SerialPin.P1
|
||||
* @param rate the new baud rate. eg: 115200
|
||||
*/
|
||||
//% weight=10
|
||||
//% help=serial/redirect-to
|
||||
//% help=serial/redirect
|
||||
//% blockId=serial_redirect block="serial|redirect to|TX %tx|RX %rx|at baud rate %rate"
|
||||
//% blockExternalInputs=1
|
||||
//% tx.fieldEditor="gridpicker" tx.fieldOptions.columns=3
|
||||
//% tx.fieldOptions.tooltips="false"
|
||||
//% rx.fieldEditor="gridpicker" rx.fieldOptions.columns=3
|
||||
//% rx.fieldOptions.tooltips="false"
|
||||
//% blockGap=8
|
||||
void redirect(SerialPin tx, SerialPin rx, BaudRate rate) {
|
||||
MicroBitPin* txp = getPin(tx); if (!tx) return;
|
||||
MicroBitPin* rxp = getPin(rx); if (!rx) return;
|
||||
|
||||
uBit.serial.redirect(txp->name, rxp->name);
|
||||
PinName txn;
|
||||
PinName rxn;
|
||||
if (tryResolvePin(tx, txn) && tryResolvePin(rx, rxn))
|
||||
uBit.serial.redirect(txn, rxn);
|
||||
uBit.serial.baud((int)rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct the serial input and output to use the USB connection.
|
||||
*/
|
||||
//% weight=9 help=serial/redirect-to-usb
|
||||
//% blockId=serial_redirect_to_usb block="serial|redirect to USB"
|
||||
void redirectToUSB() {
|
||||
uBit.serial.redirect(USBTX, USBRX);
|
||||
uBit.serial.baud(115200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of the RX buffer in bytes
|
||||
* @param size length of the rx buffer in bytes, eg: 32
|
||||
*/
|
||||
//% help=serial/set-rx-buffer-size
|
||||
//% blockId=serialSetRxBufferSize block="serial set rx buffer size to $size"
|
||||
//% advanced=true
|
||||
void setRxBufferSize(uint8_t size) {
|
||||
uBit.serial.setRxBufferSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of the TX buffer in bytes
|
||||
* @param size length of the tx buffer in bytes, eg: 32
|
||||
*/
|
||||
//% help=serial/set-tx-buffer-size
|
||||
//% blockId=serialSetTxBufferSize block="serial set tx buffer size to $size"
|
||||
//% advanced=true
|
||||
void setTxBufferSize(uint8_t size) {
|
||||
uBit.serial.setTxBufferSize(size);
|
||||
}
|
||||
}
|
||||
|
@ -5,18 +5,48 @@
|
||||
//% advanced=true
|
||||
namespace serial {
|
||||
/**
|
||||
* Prints a line of text to the serial
|
||||
* The string used to mark a new line, default is \r\n
|
||||
*/
|
||||
export let NEW_LINE = "\r\n";
|
||||
let writeLinePadding = 32;
|
||||
|
||||
/**
|
||||
* Print a line of text to the serial port
|
||||
* @param value to send over serial
|
||||
*/
|
||||
//% weight=90
|
||||
//% help=serial/write-line blockGap=8
|
||||
//% blockId=serial_writeline block="serial|write line %text"
|
||||
//% text.shadowOptions.toString=true
|
||||
export function writeLine(text: string): void {
|
||||
writeString(text + "\r\n");
|
||||
if (!text) text = "";
|
||||
serial.writeString(text);
|
||||
// pad data to the 32 byte boundary
|
||||
// to ensure apps receive the packet
|
||||
if (writeLinePadding > 0) {
|
||||
let r = (writeLinePadding - (text.length + NEW_LINE.length) % writeLinePadding) % writeLinePadding;
|
||||
for (let i = 0; i < r; ++i)
|
||||
serial.writeString(" ");
|
||||
}
|
||||
serial.writeString(NEW_LINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a numeric value to the serial
|
||||
* Sets the padding length for lines sent with "write line".
|
||||
* @param length the number of bytes alignment, eg: 0
|
||||
*
|
||||
*/
|
||||
//% weight=1
|
||||
//% help=serial/set-write-line-padding
|
||||
//% blockId=serialWriteNewLinePadding block="serial set write line padding to $length"
|
||||
//% advanced=true
|
||||
//% length.min=0 length.max=128
|
||||
export function setWriteLinePadding(length: number) {
|
||||
writeLinePadding = length | 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a numeric value to the serial port
|
||||
*/
|
||||
//% help=serial/write-number
|
||||
//% weight=89 blockGap=8
|
||||
@ -26,7 +56,22 @@ namespace serial {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a ``name: value`` pair line to the serial.
|
||||
* Print an array of numeric values as CSV to the serial port
|
||||
*/
|
||||
//% help=serial/write-numbers
|
||||
//% weight=86
|
||||
//% blockId=serial_writenumbers block="serial|write numbers %values"
|
||||
export function writeNumbers(values: number[]): void {
|
||||
if (!values) return;
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
if (i > 0) writeString(",");
|
||||
writeNumber(values[i]);
|
||||
}
|
||||
writeLine("")
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a name:value pair as a line to the serial port.
|
||||
* @param name name of the value stream, eg: x
|
||||
* @param value to write
|
||||
*/
|
||||
@ -34,11 +79,11 @@ namespace serial {
|
||||
//% help=serial/write-value
|
||||
//% blockId=serial_writevalue block="serial|write value %name|= %value"
|
||||
export function writeValue(name: string, value: number): void {
|
||||
writeString(name + ":" + value + "\r\n");
|
||||
writeLine((name ? name + ":" : "") + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line of text from the serial port.
|
||||
* Read a line of text from the serial port.
|
||||
*/
|
||||
//% help=serial/read-line
|
||||
//% blockId=serial_read_line block="serial|read line"
|
||||
@ -48,14 +93,14 @@ namespace serial {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delimiter corresponding string
|
||||
* Return the corresponding delimiter string
|
||||
*/
|
||||
//% blockId="serial_delimiter_conv" block="%del"
|
||||
//% weight=1 blockHidden=true
|
||||
export function delimiters(del: Delimiters): string {
|
||||
// even though it might not look like, this is more
|
||||
// (memory) efficient than the C++ implementation, because the
|
||||
// strings are statically allocated and take no RAM
|
||||
// strings are statically allocated and take no RAM
|
||||
switch (del) {
|
||||
case Delimiters.NewLine: return "\n"
|
||||
case Delimiters.Comma: return ","
|
||||
|
416
libs/core/shims.d.ts
vendored
@ -4,7 +4,7 @@
|
||||
/**
|
||||
* Creation, manipulation and display of LED images.
|
||||
*/
|
||||
//% color=#5C2D91 weight=31 icon="\uf03e"
|
||||
//% color=#7600A8 weight=31 icon="\uf03e"
|
||||
//% advanced=true
|
||||
declare namespace images {
|
||||
|
||||
@ -32,16 +32,16 @@ declare interface Image {
|
||||
*/
|
||||
//% help=images/plot-image
|
||||
//% parts="ledmatrix" xOffset.defl=0 shim=ImageMethods::plotImage
|
||||
plotImage(xOffset?: number): void;
|
||||
plotImage(xOffset?: int32): void;
|
||||
|
||||
/**
|
||||
* Shows an frame from the image at offset ``x offset``.
|
||||
* @param xOffset column index to start displaying the image
|
||||
*/
|
||||
//% help=images/show-image weight=80 blockNamespace=images
|
||||
//% blockId=device_show_image_offset block="show image %sprite|at offset %offset" blockGap=8
|
||||
//% parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage
|
||||
showImage(xOffset: number, interval?: number): void;
|
||||
//% blockId=device_show_image_offset block="show image %sprite(myImage)|at offset %offset"
|
||||
//% blockGap=8 parts="ledmatrix" async interval.defl=400 shim=ImageMethods::showImage
|
||||
showImage(xOffset: int32, interval?: int32): void;
|
||||
|
||||
/**
|
||||
* Draws the ``index``-th frame of the image on the screen.
|
||||
@ -49,7 +49,7 @@ declare interface Image {
|
||||
*/
|
||||
//% help=images/plot-frame weight=80
|
||||
//% parts="ledmatrix" shim=ImageMethods::plotFrame
|
||||
plotFrame(xOffset: number): void;
|
||||
plotFrame(xOffset: int32): void;
|
||||
|
||||
/**
|
||||
* Scrolls an image .
|
||||
@ -57,9 +57,10 @@ declare interface Image {
|
||||
* @param interval time between each animation step in milli seconds, eg: 200
|
||||
*/
|
||||
//% help=images/scroll-image weight=79 async blockNamespace=images
|
||||
//% blockId=device_scroll_image block="scroll image %sprite|with offset %frameoffset|and interval (ms) %delay" blockGap=8
|
||||
//% parts="ledmatrix" shim=ImageMethods::scrollImage
|
||||
scrollImage(frameOffset: number, interval: number): void;
|
||||
//% blockId=device_scroll_image
|
||||
//% block="scroll image %sprite(myImage)|with offset %frameoffset|and interval (ms) %delay"
|
||||
//% blockGap=8 parts="ledmatrix" shim=ImageMethods::scrollImage
|
||||
scrollImage(frameOffset: int32, interval: int32): void;
|
||||
|
||||
/**
|
||||
* Sets all pixels off.
|
||||
@ -73,79 +74,76 @@ declare interface Image {
|
||||
*/
|
||||
//%
|
||||
//% parts="ledmatrix" shim=ImageMethods::setPixelBrightness
|
||||
setPixelBrightness(x: number, y: number, value: number): void;
|
||||
setPixelBrightness(x: int32, y: int32, value: int32): void;
|
||||
|
||||
/**
|
||||
* Gets the pixel brightness ([0..255]) at a given position
|
||||
*/
|
||||
//%
|
||||
//% parts="ledmatrix" shim=ImageMethods::pixelBrightness
|
||||
pixelBrightness(x: number, y: number): number;
|
||||
pixelBrightness(x: int32, y: int32): int32;
|
||||
|
||||
/**
|
||||
* Gets the width in columns
|
||||
*/
|
||||
//% help=functions/width shim=ImageMethods::width
|
||||
width(): number;
|
||||
width(): int32;
|
||||
|
||||
/**
|
||||
* Gets the height in rows (always 5)
|
||||
*/
|
||||
//% shim=ImageMethods::height
|
||||
height(): number;
|
||||
height(): int32;
|
||||
|
||||
/**
|
||||
* Set a pixel state at position ``(x,y)``
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param value TODO
|
||||
* @param x pixel column
|
||||
* @param y pixel row
|
||||
* @param value pixel state
|
||||
*/
|
||||
//% help=images/set-pixel
|
||||
//% parts="ledmatrix" shim=ImageMethods::setPixel
|
||||
setPixel(x: number, y: number, value: boolean): void;
|
||||
setPixel(x: int32, y: int32, value: boolean): void;
|
||||
|
||||
/**
|
||||
* Get the pixel state at position ``(x,y)``
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param x pixel column
|
||||
* @param y pixel row
|
||||
*/
|
||||
//% help=images/pixel
|
||||
//% parts="ledmatrix" shim=ImageMethods::pixel
|
||||
pixel(x: number, y: number): boolean;
|
||||
pixel(x: int32, y: int32): boolean;
|
||||
|
||||
/**
|
||||
* Shows a particular frame of the image strip.
|
||||
* @param frame TODO
|
||||
* Show a particular frame of the image strip.
|
||||
* @param frame image frame to show
|
||||
*/
|
||||
//% weight=70 help=images/show-frame
|
||||
//% parts="ledmatrix" interval.defl=400 shim=ImageMethods::showFrame
|
||||
showFrame(frame: number, interval?: number): void;
|
||||
showFrame(frame: int32, interval?: int32): void;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides access to basic micro:bit functionality.
|
||||
*/
|
||||
//% color=#54C9C9 weight=100 icon="\uf00a"
|
||||
//% color=#1E90FF weight=116 icon="\uf00a"
|
||||
declare namespace basic {
|
||||
|
||||
/**
|
||||
* Sets the color on the build-in LED. Set to 0 to turn off.
|
||||
*/
|
||||
//% blockId=device_set_led_color block="set led to %color=color_id"
|
||||
//% blockId=device_set_led_color
|
||||
//% block="set led to %color=colorNumberPicker"
|
||||
//% weight=50 shim=basic::setLedColor
|
||||
function setLedColor(color: number): void;
|
||||
function setLedColor(color: int32): void;
|
||||
|
||||
/**
|
||||
* Scroll a number on the screen. If the number fits on the screen (i.e. is a single digit), do not scroll.
|
||||
* @param interval speed of scroll; eg: 150, 100, 200, -100
|
||||
* Sets the color on the build-in LED. Set to 0 to turn off.
|
||||
*/
|
||||
//% help=basic/show-number
|
||||
//% weight=96
|
||||
//% blockId=device_show_number block="show|number %number" blockGap=8
|
||||
//% async
|
||||
//% parts="ledmatrix" interval.defl=150 shim=basic::showNumber
|
||||
function showNumber(value: number, interval?: number): void;
|
||||
//% blockId=device_turn_rgb_led_off block="turn build-in LED off"
|
||||
//% weight=50 shim=basic::turnRgbLedOff
|
||||
function turnRgbLedOff(): void;
|
||||
|
||||
/**
|
||||
* Draws an image on the LED screen.
|
||||
@ -158,20 +156,21 @@ declare namespace basic {
|
||||
//% blockId=device_show_leds
|
||||
//% block="show leds" icon="\uf00a"
|
||||
//% parts="ledmatrix" interval.defl=400 shim=basic::showLeds
|
||||
function showLeds(leds: string, interval?: number): void;
|
||||
function showLeds(leds: string, interval?: int32): void;
|
||||
|
||||
/**
|
||||
* Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.
|
||||
* @param text the text to scroll on the screen, eg: "Hello!"
|
||||
* @param text the text to scroll on the screen, eg: "hi!"
|
||||
* @param interval how fast to shift characters; eg: 150, 100, 200, -100
|
||||
*/
|
||||
//% help=basic/show-string
|
||||
//% weight=87 blockGap=8
|
||||
//% weight=87 blockGap=16
|
||||
//% block="show|string %text"
|
||||
//% async
|
||||
//% blockId=device_print_message
|
||||
//% parts="ledmatrix" interval.defl=150 shim=basic::showString
|
||||
function showString(text: string, interval?: number): void;
|
||||
//% parts="ledmatrix"
|
||||
//% text.shadowOptions.toString=true interval.defl=150 shim=basic::showString
|
||||
function showString(text: string, interval?: int32): void;
|
||||
|
||||
/**
|
||||
* Turn off all LEDs
|
||||
@ -189,7 +188,7 @@ declare namespace basic {
|
||||
*/
|
||||
//% help=basic/show-animation imageLiteral=1 async
|
||||
//% parts="ledmatrix" interval.defl=400 shim=basic::showAnimation
|
||||
function showAnimation(leds: string, interval?: number): void;
|
||||
function showAnimation(leds: string, interval?: int32): void;
|
||||
|
||||
/**
|
||||
* Draws an image on the LED screen.
|
||||
@ -203,7 +202,7 @@ declare namespace basic {
|
||||
* Repeats the code forever in the background. On each iteration, allows other codes to run.
|
||||
* @param body code to execute
|
||||
*/
|
||||
//% help=basic/forever weight=55 blockGap=8 blockAllowMultiple=1 afterOnStart=true
|
||||
//% help=basic/forever weight=55 blockGap=16 blockAllowMultiple=1 afterOnStart=true
|
||||
//% blockId=device_forever block="forever" icon="\uf01e" shim=basic::forever
|
||||
function forever(a: () => void): void;
|
||||
|
||||
@ -212,9 +211,10 @@ declare namespace basic {
|
||||
* @param ms how long to pause for, eg: 100, 200, 500, 1000, 2000
|
||||
*/
|
||||
//% help=basic/pause weight=54
|
||||
//% async block="pause (ms) %pause"
|
||||
//% blockId=device_pause icon="\uf110" shim=basic::pause
|
||||
function pause(ms: number): void;
|
||||
//% async block="pause (ms) %pause" blockGap=16
|
||||
//% blockId=device_pause icon="\uf110"
|
||||
//% pause.shadow=timePicker shim=basic::pause
|
||||
function pause(ms: int32): void;
|
||||
}
|
||||
|
||||
|
||||
@ -227,7 +227,7 @@ declare namespace input {
|
||||
* @param button the button that needs to be pressed
|
||||
* @param body code to run when event is raised
|
||||
*/
|
||||
//% help=input/on-button-pressed weight=85 blockGap=8
|
||||
//% help=input/on-button-pressed weight=85 blockGap=16
|
||||
//% blockId=device_button_event block="on button|%NAME|pressed"
|
||||
//% parts="buttonpair" shim=input::onButtonPressed
|
||||
function onButtonPressed(button: Button, body: () => void): void;
|
||||
@ -237,18 +237,28 @@ declare namespace input {
|
||||
* @param gesture the type of gesture to track, eg: Gesture.Shake
|
||||
* @param body code to run when gesture is raised
|
||||
*/
|
||||
//% help=input/on-gesture weight=84 blockGap=8
|
||||
//% help=input/on-gesture weight=84 blockGap=16
|
||||
//% blockId=device_gesture_event block="on |%NAME"
|
||||
//% parts="accelerometer"
|
||||
//% NAME.fieldEditor="gridpicker" NAME.fieldOptions.columns=4 shim=input::onGesture
|
||||
//% NAME.fieldEditor="gestures" NAME.fieldOptions.columns=4 shim=input::onGesture
|
||||
function onGesture(gesture: Gesture, body: () => void): void;
|
||||
|
||||
/**
|
||||
* Tests if a gesture is currently detected.
|
||||
* @param gesture the type of gesture to detect, eg: Gesture.Shake
|
||||
*/
|
||||
//% help=input/is-gesture weight=10 blockGap=8
|
||||
//% blockId=deviceisgesture block="is %gesture gesture"
|
||||
//% parts="accelerometer"
|
||||
//% gesture.fieldEditor="gestures" gesture.fieldOptions.columns=4 shim=input::isGesture
|
||||
function isGesture(gesture: Gesture): boolean;
|
||||
|
||||
/**
|
||||
* Do something when a pin is touched and released again (while also touching the GND pin).
|
||||
* @param name the pin that needs to be pressed, eg: TouchPin.P0
|
||||
* @param body the code to run when the pin is pressed
|
||||
*/
|
||||
//% help=input/on-pin-pressed weight=83
|
||||
//% help=input/on-pin-pressed weight=83 blockGap=32
|
||||
//% blockId=device_pin_event block="on pin %name|pressed" shim=input::onPinPressed
|
||||
function onPinPressed(name: TouchPin, body: () => void): void;
|
||||
|
||||
@ -257,7 +267,7 @@ declare namespace input {
|
||||
* @param name the pin that needs to be released, eg: TouchPin.P0
|
||||
* @param body the code to run when the pin is released
|
||||
*/
|
||||
//% help=input/on-pin-released weight=6 blockGap=8
|
||||
//% help=input/on-pin-released weight=6 blockGap=16
|
||||
//% blockId=device_pin_released block="on pin %NAME|released"
|
||||
//% advanced=true shim=input::onPinReleased
|
||||
function onPinReleased(name: TouchPin, body: () => void): void;
|
||||
@ -269,7 +279,7 @@ declare namespace input {
|
||||
//% help=input/button-is-pressed weight=60
|
||||
//% block="button|%NAME|is pressed"
|
||||
//% blockId=device_get_button2
|
||||
//% blockGap=8
|
||||
//% icon="\uf192" blockGap=8
|
||||
//% parts="buttonpair" shim=input::buttonIsPressed
|
||||
function buttonIsPressed(button: Button): boolean;
|
||||
|
||||
@ -284,12 +294,12 @@ declare namespace input {
|
||||
|
||||
/**
|
||||
* Get the acceleration value in milli-gravitys (when the board is laying flat with the screen up, x=0, y=0 and z=-1024)
|
||||
* @param dimension TODO
|
||||
* @param dimension x, y, or z dimension, eg: Dimension.X
|
||||
*/
|
||||
//% help=input/acceleration weight=58
|
||||
//% blockId=device_acceleration block="acceleration (mg)|%NAME" blockGap=8
|
||||
//% parts="accelerometer" shim=input::acceleration
|
||||
function acceleration(dimension: Dimension): number;
|
||||
function acceleration(dimension: Dimension): int32;
|
||||
|
||||
/**
|
||||
* Reads the light level applied to the LED screen in a range from ``0`` (dark) to ``255`` bright.
|
||||
@ -297,7 +307,7 @@ declare namespace input {
|
||||
//% help=input/light-level weight=57
|
||||
//% blockId=device_get_light_level block="light level" blockGap=8
|
||||
//% parts="ledmatrix" shim=input::lightLevel
|
||||
function lightLevel(): number;
|
||||
function lightLevel(): int32;
|
||||
|
||||
/**
|
||||
* Get the current compass heading in degrees.
|
||||
@ -306,7 +316,7 @@ declare namespace input {
|
||||
//% weight=56
|
||||
//% blockId=device_heading block="compass heading (°)" blockGap=8
|
||||
//% parts="compass" shim=input::compassHeading
|
||||
function compassHeading(): number;
|
||||
function compassHeading(): int32;
|
||||
|
||||
/**
|
||||
* Gets the temperature in Celsius degrees (°C).
|
||||
@ -315,26 +325,26 @@ declare namespace input {
|
||||
//% help=input/temperature
|
||||
//% blockId=device_temperature block="temperature (°C)" blockGap=8
|
||||
//% parts="thermometer" shim=input::temperature
|
||||
function temperature(): number;
|
||||
function temperature(): int32;
|
||||
|
||||
/**
|
||||
* The pitch or roll of the device, rotation along the ``x-axis`` or ``y-axis``, in degrees.
|
||||
* @param kind TODO
|
||||
* @param kind pitch or roll
|
||||
*/
|
||||
//% help=input/rotation weight=52
|
||||
//% blockId=device_get_rotation block="rotation (°)|%NAME" blockGap=8
|
||||
//% parts="accelerometer" advanced=true shim=input::rotation
|
||||
function rotation(kind: Rotation): number;
|
||||
function rotation(kind: Rotation): int32;
|
||||
|
||||
/**
|
||||
* Get the magnetic force value in ``micro-Teslas`` (``µT``). This function is not supported in the simulator.
|
||||
* @param dimension TODO
|
||||
* @param dimension the x, y, or z dimension, eg: Dimension.X
|
||||
*/
|
||||
//% help=input/magnetic-force weight=51
|
||||
//% blockId=device_get_magnetic_force block="magnetic force (µT)|%NAME" blockGap=8
|
||||
//% parts="compass"
|
||||
//% advanced=true shim=input::magneticForce
|
||||
function magneticForce(dimension: Dimension): number;
|
||||
function magneticForce(dimension: Dimension): int32;
|
||||
|
||||
/**
|
||||
* Gets the number of milliseconds elapsed since power on.
|
||||
@ -342,7 +352,7 @@ declare namespace input {
|
||||
//% help=input/running-time weight=50 blockGap=8
|
||||
//% blockId=device_get_running_time block="running time (ms)"
|
||||
//% advanced=true shim=input::runningTime
|
||||
function runningTime(): number;
|
||||
function runningTime(): int32;
|
||||
|
||||
/**
|
||||
* Gets the number of microseconds elapsed since power on.
|
||||
@ -350,13 +360,14 @@ declare namespace input {
|
||||
//% help=input/running-time-micros weight=49
|
||||
//% blockId=device_get_running_time_micros block="running time (micros)"
|
||||
//% advanced=true shim=input::runningTimeMicros
|
||||
function runningTimeMicros(): number;
|
||||
function runningTimeMicros(): int32;
|
||||
|
||||
/**
|
||||
* Obsolete, compass calibration is automatic.
|
||||
*/
|
||||
//% help=input/calibrate-compass advanced=true
|
||||
//% blockId="input_compass_calibrate" block="calibrate compass" shim=input::calibrateCompass
|
||||
//% blockId="input_compass_calibrate" block="calibrate compass"
|
||||
//% weight=45 shim=input::calibrateCompass
|
||||
function calibrateCompass(): void;
|
||||
|
||||
/**
|
||||
@ -397,7 +408,7 @@ declare namespace control {
|
||||
*/
|
||||
//% help=control/wait-micros weight=29
|
||||
//% blockId="control_wait_us" block="wait (µs)%micros" shim=control::waitMicros
|
||||
function waitMicros(micros: number): void;
|
||||
function waitMicros(micros: int32): void;
|
||||
|
||||
/**
|
||||
* Raises an event in the event bus.
|
||||
@ -408,15 +419,15 @@ declare namespace control {
|
||||
//% weight=21 blockGap=12 blockId="control_raise_event" block="raise event|from source %src=control_event_source_id|with value %value=control_event_value_id" blockExternalInputs=1
|
||||
//% help=control/raise-event
|
||||
//% mode.defl=1 shim=control::raiseEvent
|
||||
function raiseEvent(src: number, value: number, mode?: EventCreationMode): void;
|
||||
function raiseEvent(src: int32, value: int32, mode?: EventCreationMode): void;
|
||||
|
||||
/**
|
||||
* Raises an event in the event bus.
|
||||
* Registers an event handler.
|
||||
*/
|
||||
//% weight=20 blockGap=8 blockId="control_on_event" block="on event|from %src=control_event_source_id|with value %value=control_event_value_id"
|
||||
//% help=control/on-event
|
||||
//% blockExternalInputs=1 shim=control::onEvent
|
||||
function onEvent(src: number, value: number, handler: () => void): void;
|
||||
//% blockExternalInputs=1 flags.defl=0 shim=control::onEvent
|
||||
function onEvent(src: int32, value: int32, handler: () => void, flags?: int32): void;
|
||||
|
||||
/**
|
||||
* Gets the value of the last event executed on the bus
|
||||
@ -424,7 +435,7 @@ declare namespace control {
|
||||
//% blockId=control_event_value" block="event value"
|
||||
//% help=control/event-value
|
||||
//% weight=18 shim=control::eventValue
|
||||
function eventValue(): number;
|
||||
function eventValue(): int32;
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the last event executed on the bus
|
||||
@ -432,10 +443,10 @@ declare namespace control {
|
||||
//% blockId=control_event_timestamp" block="event timestamp"
|
||||
//% help=control/event-timestamp
|
||||
//% weight=19 blockGap=8 shim=control::eventTimestamp
|
||||
function eventTimestamp(): number;
|
||||
function eventTimestamp(): int32;
|
||||
|
||||
/**
|
||||
* Gets a friendly name for the device derived from the its serial number
|
||||
* Make a friendly name for the device based on its serial number
|
||||
*/
|
||||
//% blockId="control_device_name" block="device name" weight=10 blockGap=8
|
||||
//% advanced=true shim=control::deviceName
|
||||
@ -446,7 +457,20 @@ declare namespace control {
|
||||
*/
|
||||
//% blockId="control_device_serial_number" block="device serial number" weight=9
|
||||
//% advanced=true shim=control::deviceSerialNumber
|
||||
function deviceSerialNumber(): number;
|
||||
function deviceSerialNumber(): int32;
|
||||
|
||||
/**
|
||||
* Informs simulator/runtime of a MIDI message
|
||||
* Internal function to support the simulator.
|
||||
*/
|
||||
//% part=midioutput blockHidden=1 shim=control::__midiSend
|
||||
function __midiSend(buffer: Buffer): void;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
//% shim=control::__log
|
||||
function __log(text: string): void;
|
||||
}
|
||||
|
||||
|
||||
@ -462,8 +486,9 @@ declare namespace led {
|
||||
//% help=led/plot weight=78
|
||||
//% blockId=device_plot block="plot|x %x|y %y" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4 shim=led::plot
|
||||
function plot(x: number, y: number): void;
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::plot
|
||||
function plot(x: int32, y: int32): void;
|
||||
|
||||
/**
|
||||
* Turn on the specified LED with specific brightness using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.
|
||||
@ -475,30 +500,33 @@ declare namespace led {
|
||||
//% blockId=device_plot_brightness block="plot|x %x|y %y|brightness %brightness" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4 brightness.min=0 brightness.max=255
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1
|
||||
//% advanced=true shim=led::plotBrightness
|
||||
function plotBrightness(x: number, y: number, brightness: number): void;
|
||||
function plotBrightness(x: int32, y: int32, brightness: int32): void;
|
||||
|
||||
/**
|
||||
* Turn off the specified LED using x, y coordinates (x is horizontal, y is vertical). (0,0) is upper left.
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param x the horizontal coordinate of the LED
|
||||
* @param y the vertical coordinate of the LED
|
||||
*/
|
||||
//% help=led/unplot weight=77
|
||||
//% blockId=device_unplot block="unplot|x %x|y %y" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4 shim=led::unplot
|
||||
function unplot(x: number, y: number): void;
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::unplot
|
||||
function unplot(x: int32, y: int32): void;
|
||||
|
||||
/**
|
||||
* Get the on/off state of the specified LED using x, y coordinates. (0,0) is upper left.
|
||||
* @param x TODO
|
||||
* @param y TODO
|
||||
* @param x the horizontal coordinate of the LED
|
||||
* @param y the vertical coordinate of the LED
|
||||
*/
|
||||
//% help=led/point weight=76
|
||||
//% blockId=device_point block="point|x %x|y %y"
|
||||
//% parts="ledmatrix"
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4 shim=led::point
|
||||
function point(x: number, y: number): boolean;
|
||||
//% x.min=0 x.max=4 y.min=0 y.max=4
|
||||
//% x.fieldOptions.precision=1 y.fieldOptions.precision=1 shim=led::point
|
||||
function point(x: int32, y: int32): boolean;
|
||||
|
||||
/**
|
||||
* Get the screen brightness from 0 (off) to 255 (full bright).
|
||||
@ -507,7 +535,7 @@ declare namespace led {
|
||||
//% blockId=device_get_brightness block="brightness" blockGap=8
|
||||
//% parts="ledmatrix"
|
||||
//% advanced=true shim=led::brightness
|
||||
function brightness(): number;
|
||||
function brightness(): int32;
|
||||
|
||||
/**
|
||||
* Set the screen brightness from 0 (off) to 255 (full bright).
|
||||
@ -518,7 +546,7 @@ declare namespace led {
|
||||
//% parts="ledmatrix"
|
||||
//% advanced=true
|
||||
//% value.min=0 value.max=255 shim=led::setBrightness
|
||||
function setBrightness(value: number): void;
|
||||
function setBrightness(value: int32): void;
|
||||
|
||||
/**
|
||||
* Cancels the current animation and clears other pending animations.
|
||||
@ -534,7 +562,8 @@ declare namespace led {
|
||||
* @param mode mode the display mode in which the screen operates
|
||||
*/
|
||||
//% weight=1 help=led/set-display-mode
|
||||
//% parts="ledmatrix" advanced=true shim=led::setDisplayMode
|
||||
//% parts="ledmatrix" advanced=true weight=1
|
||||
//% blockId="led_set_display_mode" block="set display mode $mode" shim=led::setDisplayMode
|
||||
function setDisplayMode(mode: DisplayMode): void;
|
||||
|
||||
/**
|
||||
@ -544,7 +573,7 @@ declare namespace led {
|
||||
function displayMode(): DisplayMode;
|
||||
|
||||
/**
|
||||
* Turns on or off the display
|
||||
* Turns on or off the display
|
||||
*/
|
||||
//% help=led/enable blockId=device_led_enable block="led enable %on"
|
||||
//% advanced=true parts="ledmatrix" shim=led::enable
|
||||
@ -571,7 +600,7 @@ declare namespace motors {
|
||||
*/
|
||||
//% blockId=motor_on block="motor on at %percent"
|
||||
//% parts=dcmotor weight=90 blockGap=8 shim=motors::motorPower
|
||||
function motorPower(power: number): void;
|
||||
function motorPower(power: int32): void;
|
||||
|
||||
/**
|
||||
* Send break, coast or sleep commands to the motor. Has no effect in dual-motor mode.
|
||||
@ -585,7 +614,7 @@ declare namespace motors {
|
||||
*/
|
||||
//% blockId=block_dual_motor block="motor %motor|at %percent"
|
||||
//% weight=80 shim=motors::dualMotorPower
|
||||
function dualMotorPower(motor: Motor, duty_percent: number): void;
|
||||
function dualMotorPower(motor: Motor, duty_percent: int32): void;
|
||||
}
|
||||
declare namespace music {
|
||||
|
||||
@ -596,7 +625,7 @@ declare namespace music {
|
||||
*/
|
||||
//%
|
||||
//% parts="speaker" async useEnumVal=1 shim=music::speakerPlayTone
|
||||
function speakerPlayTone(frequency: number, ms: number): void;
|
||||
function speakerPlayTone(frequency: int32, ms: int32): void;
|
||||
}
|
||||
declare namespace pins {
|
||||
|
||||
@ -608,7 +637,7 @@ declare namespace pins {
|
||||
//% blockId=device_get_digital_pin block="digital read|pin %name" blockGap=8
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" shim=pins::digitalReadPin
|
||||
function digitalReadPin(name: DigitalPin): number;
|
||||
function digitalReadPin(name: DigitalPin): int32;
|
||||
|
||||
/**
|
||||
* Set a pin or connector value to either 0 or 1.
|
||||
@ -620,7 +649,7 @@ declare namespace pins {
|
||||
//% value.min=0 value.max=1
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" shim=pins::digitalWritePin
|
||||
function digitalWritePin(name: DigitalPin, value: number): void;
|
||||
function digitalWritePin(name: DigitalPin, value: int32): void;
|
||||
|
||||
/**
|
||||
* Read the connector value as analog, that is, as a value comprised between 0 and 1023.
|
||||
@ -629,8 +658,8 @@ declare namespace pins {
|
||||
//% help=pins/analog-read-pin weight=25
|
||||
//% blockId=device_get_analog_pin block="analog read|pin %name" blockGap="8"
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" shim=pins::analogReadPin
|
||||
function analogReadPin(name: AnalogPin): number;
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogReadPin
|
||||
function analogReadPin(name: AnalogPin): int32;
|
||||
|
||||
/**
|
||||
* Set the connector value as analog. Value must be comprised between 0 and 1023.
|
||||
@ -641,11 +670,11 @@ declare namespace pins {
|
||||
//% blockId=device_set_analog_pin block="analog write|pin %name|to %value" blockGap=8
|
||||
//% value.min=0 value.max=1023
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" shim=pins::analogWritePin
|
||||
function analogWritePin(name: AnalogPin, value: number): void;
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogWritePin
|
||||
function analogWritePin(name: AnalogPin, value: int32): void;
|
||||
|
||||
/**
|
||||
* Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.
|
||||
* Configure the pulse-width modulation (PWM) period of the analog output in microseconds.
|
||||
* If this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.
|
||||
* @param name analog pin to set period to, eg: AnalogPin.P0
|
||||
* @param micros period in micro seconds. eg:20000
|
||||
@ -654,42 +683,42 @@ declare namespace pins {
|
||||
//% blockId=device_set_analog_period block="analog set period|pin %pin|to (µs)%micros"
|
||||
//% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4
|
||||
//% pin.fieldOptions.tooltips="false" shim=pins::analogSetPeriod
|
||||
function analogSetPeriod(name: AnalogPin, micros: number): void;
|
||||
function analogSetPeriod(name: AnalogPin, micros: int32): void;
|
||||
|
||||
/**
|
||||
* Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``.
|
||||
* Configure the pin as a digital input and generate an event when the pin is pulsed either high or low.
|
||||
* @param name digital pin to register to, eg: DigitalPin.P0
|
||||
* @param pulse the value of the pulse, eg: PulseValue.High
|
||||
*/
|
||||
//% help=pins/on-pulsed weight=22 blockGap=8 advanced=true
|
||||
//% help=pins/on-pulsed weight=22 blockGap=16 advanced=true
|
||||
//% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse"
|
||||
//% pin.fieldEditor="gridpicker" pin.fieldOptions.columns=4
|
||||
//% pin.fieldOptions.tooltips="false" pin.fieldOptions.width="300" shim=pins::onPulsed
|
||||
function onPulsed(name: DigitalPin, pulse: PulseValue, body: () => void): void;
|
||||
|
||||
/**
|
||||
* Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler.
|
||||
* Get the duration of the last pulse in microseconds. This function should be called from a ``onPulsed`` handler.
|
||||
*/
|
||||
//% help=pins/pulse-duration advanced=true
|
||||
//% blockId=pins_pulse_duration block="pulse duration (µs)"
|
||||
//% weight=21 blockGap=8 shim=pins::pulseDuration
|
||||
function pulseDuration(): number;
|
||||
function pulseDuration(): int32;
|
||||
|
||||
/**
|
||||
* Returns the duration of a pulse in microseconds
|
||||
* Return the duration of a pulse at a pin in microseconds.
|
||||
* @param name the pin which measures the pulse, eg: DigitalPin.P0
|
||||
* @param value the value of the pulse, eg: PulseValue.High
|
||||
* @param maximum duration in micro-seconds
|
||||
* @param maximum duration in microseconds
|
||||
*/
|
||||
//% blockId="pins_pulse_in" block="pulse in (µs)|pin %name|pulsed %value"
|
||||
//% weight=20 advanced=true
|
||||
//% help=pins/pulse-in
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="300" maxDuration.defl=2000000 shim=pins::pulseIn
|
||||
function pulseIn(name: DigitalPin, value: PulseValue, maxDuration?: number): number;
|
||||
function pulseIn(name: DigitalPin, value: PulseValue, maxDuration?: int32): int32;
|
||||
|
||||
/**
|
||||
* Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
|
||||
* Write a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
|
||||
* @param name pin to write to, eg: AnalogPin.P0
|
||||
* @param value angle or rotation speed, eg:180,90,0
|
||||
*/
|
||||
@ -698,41 +727,41 @@ declare namespace pins {
|
||||
//% parts=microservo trackArgs=0
|
||||
//% value.min=0 value.max=180
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" shim=pins::servoWritePin
|
||||
function servoWritePin(name: AnalogPin, value: number): void;
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::servoWritePin
|
||||
function servoWritePin(name: AnalogPin, value: int32): void;
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.
|
||||
* Configure the IO pin as an analog/pwm output and set a pulse width. The period is 20 ms period and the pulse width is set based on the value given in **microseconds** or `1/1000` milliseconds.
|
||||
* @param name pin name
|
||||
* @param micros pulse duration in micro seconds, eg:1500
|
||||
*/
|
||||
//% help=pins/servo-set-pulse weight=19
|
||||
//% blockId=device_set_servo_pulse block="servo set pulse|pin %value|to (µs) %micros"
|
||||
//% value.fieldEditor="gridpicker" value.fieldOptions.columns=4
|
||||
//% value.fieldOptions.tooltips="false" shim=pins::servoSetPulse
|
||||
function servoSetPulse(name: AnalogPin, micros: number): void;
|
||||
//% value.fieldOptions.tooltips="false" value.fieldOptions.width="250" shim=pins::servoSetPulse
|
||||
function servoSetPulse(name: AnalogPin, micros: int32): void;
|
||||
|
||||
/**
|
||||
* Sets the pin used when using `analog pitch` or music.
|
||||
* Set the pin used when using analog pitch or music.
|
||||
* @param name pin to modulate pitch from
|
||||
*/
|
||||
//% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name"
|
||||
//% help=pins/analog-set-pitch-pin weight=3 advanced=true
|
||||
//% name.fieldEditor="gridpicker" name.fieldOptions.columns=4
|
||||
//% name.fieldOptions.tooltips="false" shim=pins::analogSetPitchPin
|
||||
//% name.fieldOptions.tooltips="false" name.fieldOptions.width="250" shim=pins::analogSetPitchPin
|
||||
function analogSetPitchPin(name: AnalogPin): void;
|
||||
|
||||
/**
|
||||
* Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.
|
||||
* Emit a plse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.
|
||||
* @param frequency frequency to modulate in Hz.
|
||||
* @param ms duration of the pitch in milli seconds.
|
||||
*/
|
||||
//% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms"
|
||||
//% help=pins/analog-pitch weight=4 async advanced=true blockGap=8 shim=pins::analogPitch
|
||||
function analogPitch(frequency: number, ms: number): void;
|
||||
function analogPitch(frequency: int32, ms: int32): void;
|
||||
|
||||
/**
|
||||
* Configures the pull of this pin.
|
||||
* Configure the pull directiion of of a pin.
|
||||
* @param name pin to set the pull mode on, eg: DigitalPin.P0
|
||||
* @param pull one of the mbed pull configurations, eg: PinPullMode.PullUp
|
||||
*/
|
||||
@ -743,7 +772,7 @@ declare namespace pins {
|
||||
function setPull(name: DigitalPin, pull: PinPullMode): void;
|
||||
|
||||
/**
|
||||
* Configures the events emitted by this pin. Events can be subscribed to
|
||||
* Configure the events emitted by this pin. Events can be subscribed to
|
||||
* using ``control.onEvent()``.
|
||||
* @param name pin to set the event mode on, eg: DigitalPin.P0
|
||||
* @param type the type of events for this pin to emit, eg: PinEventType.Edge
|
||||
@ -759,19 +788,19 @@ declare namespace pins {
|
||||
* @param size number of bytes in the buffer
|
||||
*/
|
||||
//% shim=pins::createBuffer
|
||||
function createBuffer(size: number): Buffer;
|
||||
function createBuffer(size: int32): Buffer;
|
||||
|
||||
/**
|
||||
* Read `size` bytes from a 7-bit I2C `address`.
|
||||
*/
|
||||
//% repeat.defl=0 shim=pins::i2cReadBuffer
|
||||
function i2cReadBuffer(address: number, size: number, repeat?: boolean): Buffer;
|
||||
function i2cReadBuffer(address: int32, size: int32, repeat?: boolean): Buffer;
|
||||
|
||||
/**
|
||||
* Write bytes to a 7-bit I2C `address`.
|
||||
*/
|
||||
//% repeat.defl=0 shim=pins::i2cWriteBuffer
|
||||
function i2cWriteBuffer(address: number, buf: Buffer, repeat?: boolean): void;
|
||||
function i2cWriteBuffer(address: int32, buf: Buffer, repeat?: boolean): int32;
|
||||
|
||||
/**
|
||||
* Write to the SPI slave and return the response
|
||||
@ -779,48 +808,48 @@ declare namespace pins {
|
||||
*/
|
||||
//% help=pins/spi-write weight=5 advanced=true
|
||||
//% blockId=spi_write block="spi write %value" shim=pins::spiWrite
|
||||
function spiWrite(value: number): number;
|
||||
function spiWrite(value: int32): int32;
|
||||
|
||||
/**
|
||||
* Sets the SPI frequency
|
||||
* Set the SPI frequency
|
||||
* @param frequency the clock frequency, eg: 1000000
|
||||
*/
|
||||
//% help=pins/spi-frequency weight=4 advanced=true
|
||||
//% blockId=spi_frequency block="spi frequency %frequency" shim=pins::spiFrequency
|
||||
function spiFrequency(frequency: number): void;
|
||||
function spiFrequency(frequency: int32): void;
|
||||
|
||||
/**
|
||||
* Sets the SPI bits and mode
|
||||
* Set the SPI bits and mode
|
||||
* @param bits the number of bits, eg: 8
|
||||
* @param mode the mode, eg: 3
|
||||
*/
|
||||
//% help=pins/spi-format weight=3 advanced=true
|
||||
//% blockId=spi_format block="spi format|bits %bits|mode %mode" shim=pins::spiFormat
|
||||
function spiFormat(bits: number, mode: number): void;
|
||||
function spiFormat(bits: int32, mode: int32): void;
|
||||
|
||||
/**
|
||||
* Sets the MOSI, MISO, SCK pins used by the SPI instance
|
||||
* Set the MOSI, MISO, SCK pins used by the SPI connection
|
||||
*
|
||||
*/
|
||||
//% help=pins/spi-pins weight=2 advanced=true
|
||||
//% blockId=spi_pins block="spi set pins|MOSI %mosi|MISO %miso|SCK %sck"
|
||||
//% mosi.fieldEditor="gridpicker" mosi.fieldOptions.columns=4
|
||||
//% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="300"
|
||||
//% mosi.fieldOptions.tooltips="false" mosi.fieldOptions.width="250"
|
||||
//% miso.fieldEditor="gridpicker" miso.fieldOptions.columns=4
|
||||
//% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="300"
|
||||
//% miso.fieldOptions.tooltips="false" miso.fieldOptions.width="250"
|
||||
//% sck.fieldEditor="gridpicker" sck.fieldOptions.columns=4
|
||||
//% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="300" shim=pins::spiPins
|
||||
//% sck.fieldOptions.tooltips="false" sck.fieldOptions.width="250" shim=pins::spiPins
|
||||
function spiPins(mosi: DigitalPin, miso: DigitalPin, sck: DigitalPin): void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//% weight=2 color=30
|
||||
//% weight=2 color=#002050 icon="\uf287"
|
||||
//% advanced=true
|
||||
declare namespace serial {
|
||||
|
||||
/**
|
||||
* Reads a line of text from the serial port and returns the buffer when the delimiter is met.
|
||||
* Read a line of text from the serial port and return the buffer when the delimiter is met.
|
||||
* @param delimiter text delimiter that separates each text chunk
|
||||
*/
|
||||
//% help=serial/read-until
|
||||
@ -829,14 +858,15 @@ declare namespace serial {
|
||||
function readUntil(delimiter: string): string;
|
||||
|
||||
/**
|
||||
* Reads the buffered received data as a string
|
||||
* Read the buffered received data as a string
|
||||
*/
|
||||
//% help=serial/read-string
|
||||
//% blockId=serial_read_buffer block="serial|read string"
|
||||
//% weight=18 shim=serial::readString
|
||||
function readString(): string;
|
||||
|
||||
/**
|
||||
* Registers an event to be fired when one of the delimiter is matched.
|
||||
* Register an event to be fired when one of the delimiter is matched.
|
||||
* @param delimiters the characters to match received characters against.
|
||||
*/
|
||||
//% help=serial/on-data-received
|
||||
@ -844,81 +874,169 @@ declare namespace serial {
|
||||
function onDataReceived(delimiters: string, body: () => void): void;
|
||||
|
||||
/**
|
||||
* Sends a piece of text through Serial connection.
|
||||
* Send a piece of text through the serial connection.
|
||||
*/
|
||||
//% help=serial/write-string
|
||||
//% weight=87
|
||||
//% blockId=serial_writestring block="serial|write string %text" shim=serial::writeString
|
||||
//% weight=87 blockGap=8
|
||||
//% blockId=serial_writestring block="serial|write string %text"
|
||||
//% text.shadowOptions.toString=true shim=serial::writeString
|
||||
function writeString(text: string): void;
|
||||
|
||||
/**
|
||||
* Dynamically configuring the serial instance to use pins other than USBTX and USBRX.
|
||||
* @param tx the new transmission pins, eg: SerialPin.P0
|
||||
* Send a buffer through serial connection
|
||||
*/
|
||||
//% blockId=serial_writebuffer block="serial|write buffer %buffer=serial_readbuffer"
|
||||
//% help=serial/write-buffer advanced=true weight=6 shim=serial::writeBuffer
|
||||
function writeBuffer(buffer: Buffer): void;
|
||||
|
||||
/**
|
||||
* Read multiple characters from the receive buffer. Pause until enough characters are present.
|
||||
* @param length default buffer length, eg: 64
|
||||
*/
|
||||
//% blockId=serial_readbuffer block="serial|read buffer %length"
|
||||
//% help=serial/read-buffer advanced=true weight=5 shim=serial::readBuffer
|
||||
function readBuffer(length: int32): Buffer;
|
||||
|
||||
/**
|
||||
* Set the serial input and output to use pins instead of the USB connection.
|
||||
* @param tx the new transmission pin, eg: SerialPin.P0
|
||||
* @param rx the new reception pin, eg: SerialPin.P1
|
||||
* @param rate the new baud rate. eg: 115200
|
||||
*/
|
||||
//% weight=10
|
||||
//% help=serial/redirect-to
|
||||
//% help=serial/redirect
|
||||
//% blockId=serial_redirect block="serial|redirect to|TX %tx|RX %rx|at baud rate %rate"
|
||||
//% blockExternalInputs=1 shim=serial::redirect
|
||||
//% blockExternalInputs=1
|
||||
//% tx.fieldEditor="gridpicker" tx.fieldOptions.columns=3
|
||||
//% tx.fieldOptions.tooltips="false"
|
||||
//% rx.fieldEditor="gridpicker" rx.fieldOptions.columns=3
|
||||
//% rx.fieldOptions.tooltips="false"
|
||||
//% blockGap=8 shim=serial::redirect
|
||||
function redirect(tx: SerialPin, rx: SerialPin, rate: BaudRate): void;
|
||||
|
||||
/**
|
||||
* Direct the serial input and output to use the USB connection.
|
||||
*/
|
||||
//% weight=9 help=serial/redirect-to-usb
|
||||
//% blockId=serial_redirect_to_usb block="serial|redirect to USB" shim=serial::redirectToUSB
|
||||
function redirectToUSB(): void;
|
||||
|
||||
/**
|
||||
* Sets the size of the RX buffer in bytes
|
||||
* @param size length of the rx buffer in bytes, eg: 32
|
||||
*/
|
||||
//% help=serial/set-rx-buffer-size
|
||||
//% blockId=serialSetRxBufferSize block="serial set rx buffer size to $size"
|
||||
//% advanced=true shim=serial::setRxBufferSize
|
||||
function setRxBufferSize(size: uint8): void;
|
||||
|
||||
/**
|
||||
* Sets the size of the TX buffer in bytes
|
||||
* @param size length of the tx buffer in bytes, eg: 32
|
||||
*/
|
||||
//% help=serial/set-tx-buffer-size
|
||||
//% blockId=serialSetTxBufferSize block="serial set tx buffer size to $size"
|
||||
//% advanced=true shim=serial::setTxBufferSize
|
||||
function setTxBufferSize(size: uint8): void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte
|
||||
declare interface Buffer {
|
||||
/**
|
||||
* Reads an unsigned byte at a particular location
|
||||
*/
|
||||
//% shim=BufferMethods::getUint8
|
||||
getUint8(off: int32): int32;
|
||||
|
||||
/**
|
||||
* Writes an unsigned byte at a particular location
|
||||
*/
|
||||
//% shim=BufferMethods::setUint8
|
||||
setUint8(off: int32, v: int32): void;
|
||||
|
||||
/**
|
||||
* Write a number in specified format in the buffer.
|
||||
*/
|
||||
//% shim=BufferMethods::setNumber
|
||||
setNumber(format: NumberFormat, offset: number, value: number): void;
|
||||
setNumber(format: NumberFormat, offset: int32, value: number): void;
|
||||
|
||||
/**
|
||||
* Read a number in specified format from the buffer.
|
||||
*/
|
||||
//% shim=BufferMethods::getNumber
|
||||
getNumber(format: NumberFormat, offset: number): number;
|
||||
getNumber(format: NumberFormat, offset: int32): number;
|
||||
|
||||
/** Returns the length of a Buffer object. */
|
||||
//% property shim=BufferMethods::length
|
||||
length: number;
|
||||
length: int32;
|
||||
|
||||
/**
|
||||
* Fill (a fragment) of the buffer with given value.
|
||||
*/
|
||||
//% offset.defl=0 length.defl=-1 shim=BufferMethods::fill
|
||||
fill(value: number, offset?: number, length?: number): void;
|
||||
fill(value: int32, offset?: int32, length?: int32): void;
|
||||
|
||||
/**
|
||||
* Return a copy of a fragment of a buffer.
|
||||
*/
|
||||
//% offset.defl=0 length.defl=-1 shim=BufferMethods::slice
|
||||
slice(offset?: number, length?: number): Buffer;
|
||||
slice(offset?: int32, length?: int32): Buffer;
|
||||
|
||||
/**
|
||||
* Shift buffer left in place, with zero padding.
|
||||
* @param offset number of bytes to shift; use negative value to shift right
|
||||
* @param start start offset in buffer. Default is 0.
|
||||
* @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1
|
||||
* @param length number of elements in buffer. If negative, length is set as the buffer length minus
|
||||
* start. eg: -1
|
||||
*/
|
||||
//% start.defl=0 length.defl=-1 shim=BufferMethods::shift
|
||||
shift(offset: number, start?: number, length?: number): void;
|
||||
shift(offset: int32, start?: int32, length?: int32): void;
|
||||
|
||||
/**
|
||||
* Convert a buffer to string assuming UTF8 encoding
|
||||
*/
|
||||
//% shim=BufferMethods::toString
|
||||
toString(): string;
|
||||
|
||||
/**
|
||||
* Convert a buffer to its hexadecimal representation.
|
||||
*/
|
||||
//% shim=BufferMethods::toHex
|
||||
toHex(): string;
|
||||
|
||||
/**
|
||||
* Rotate buffer left in place.
|
||||
* @param offset number of bytes to shift; use negative value to shift right
|
||||
* @param start start offset in buffer. Default is 0.
|
||||
* @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1
|
||||
* @param length number of elements in buffer. If negative, length is set as the buffer length minus
|
||||
* start. eg: -1
|
||||
*/
|
||||
//% start.defl=0 length.defl=-1 shim=BufferMethods::rotate
|
||||
rotate(offset: number, start?: number, length?: number): void;
|
||||
rotate(offset: int32, start?: int32, length?: int32): void;
|
||||
|
||||
/**
|
||||
* Write contents of `src` at `dstOffset` in current buffer.
|
||||
*/
|
||||
//% shim=BufferMethods::write
|
||||
write(dstOffset: number, src: Buffer): void;
|
||||
write(dstOffset: int32, src: Buffer): void;
|
||||
}
|
||||
declare namespace control {
|
||||
|
||||
/**
|
||||
* Create a new zero-initialized buffer.
|
||||
* @param size number of bytes in the buffer
|
||||
*/
|
||||
//% shim=control::createBuffer
|
||||
function createBuffer(size: int32): Buffer;
|
||||
|
||||
/**
|
||||
* Create a new buffer with UTF8-encoded string
|
||||
* @param str the string to put in the buffer
|
||||
*/
|
||||
//% shim=control::createBufferFromUTF8
|
||||
function createBufferFromUTF8(str: string): Buffer;
|
||||
}
|
||||
|
||||
// Auto-generated. Do not edit. Really.
|
||||
|