Implement tagged integers in C++ (#813)
* Start on the C++ conversion for tagged ints
This commit is contained in:
		
				
					committed by
					
						
						Sam El-Husseini
					
				
			
			
				
	
			
			
			
						parent
						
							01c7c0b588
						
					
				
				
					commit
					cad13785e2
				
			@@ -87,15 +87,15 @@ namespace bluetooth {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    //%
 | 
			
		||||
    void uartWriteString(StringData *data) {
 | 
			
		||||
    void uartWriteString(String data) {
 | 
			
		||||
        startUartService();
 | 
			
		||||
    	uart->send(ManagedString(data));
 | 
			
		||||
    	uart->send(MSTR(data));
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    //%
 | 
			
		||||
    StringData* uartReadUntil(StringData *del) {
 | 
			
		||||
    String uartReadUntil(String del) {
 | 
			
		||||
        startUartService();
 | 
			
		||||
        return uart->readUntil(ManagedString(del)).leakData();
 | 
			
		||||
        return PSTR(uart->readUntil(MSTR(del)));
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -104,9 +104,9 @@ namespace bluetooth {
 | 
			
		||||
    */
 | 
			
		||||
    //% help=bluetooth/on-uart-data-received
 | 
			
		||||
    //% weight=18 blockId=bluetooth_on_data_received block="bluetooth|on data received %delimiters=serial_delimiter_conv"
 | 
			
		||||
    void onUartDataReceived(StringData* delimiters, Action body) {
 | 
			
		||||
    void onUartDataReceived(String delimiters, Action body) {
 | 
			
		||||
      startUartService();
 | 
			
		||||
      uart->eventOn(ManagedString(delimiters));
 | 
			
		||||
      uart->eventOn(MSTR(delimiters));
 | 
			
		||||
      registerWithDal(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH, body);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -142,10 +142,10 @@ namespace bluetooth {
 | 
			
		||||
    //% blockId=eddystone_advertise_url block="bluetooth advertise url %url|with power %power|connectable %connectable"
 | 
			
		||||
    //% parts=bluetooth weight=11 blockGap=8
 | 
			
		||||
    //% help=bluetooth/advertise-url blockExternalInputs=1
 | 
			
		||||
    void advertiseUrl(StringData* url, int power, bool connectable) {
 | 
			
		||||
    void advertiseUrl(String url, int power, bool connectable) {
 | 
			
		||||
        power = min(MICROBIT_BLE_POWER_LEVELS-1, max(0, power));
 | 
			
		||||
        int8_t level = CALIBRATED_POWERS[power];
 | 
			
		||||
        uBit.bleManager.advertiseEddystoneUrl(ManagedString(url), level, connectable);
 | 
			
		||||
        uBit.bleManager.advertiseEddystoneUrl(MSTR(url), level, connectable);
 | 
			
		||||
        uBit.bleManager.setTransmitPower(power);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -157,14 +157,12 @@ namespace bluetooth {
 | 
			
		||||
    */
 | 
			
		||||
    //% parts=bluetooth weight=12 advanced=true
 | 
			
		||||
    void advertiseUidBuffer(Buffer nsAndInstance, int power, bool connectable) {
 | 
			
		||||
        ManagedBuffer buf(nsAndInstance);
 | 
			
		||||
        if (buf.length() != 16) return;
 | 
			
		||||
        auto buf = nsAndInstance;
 | 
			
		||||
        if (buf->length != 16) return;
 | 
			
		||||
 | 
			
		||||
        power = min(MICROBIT_BLE_POWER_LEVELS-1, max(0, power));
 | 
			
		||||
        int8_t level = CALIBRATED_POWERS[power];
 | 
			
		||||
        uint8_t uidNs[10]; buf.readBytes(uidNs, 0, 10);
 | 
			
		||||
        uint8_t uidInst[6]; buf.readBytes(uidInst, 10, 6);
 | 
			
		||||
        uBit.bleManager.advertiseEddystoneUid((const char*)uidNs, (const char*)uidInst, level, connectable);
 | 
			
		||||
        uBit.bleManager.advertiseEddystoneUid((const char*)buf->data, (const char*)buf->data + 10, level, connectable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
@@ -47,16 +47,17 @@
 | 
			
		||||
  "Buffer.fill": "Fill (a fragment) of the buffer with given value.",
 | 
			
		||||
  "Buffer.getNumber": "Read a number in specified format from the buffer.",
 | 
			
		||||
  "Buffer.length": "Returns the length of a Buffer object.",
 | 
			
		||||
  "Buffer.rotate": "Rotate buffer left in place.",
 | 
			
		||||
  "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.shift": "Shift buffer left in place, with zero padding.\n\n\n\nstart. eg: -1",
 | 
			
		||||
  "Buffer.shift|param|length": "number of elements in buffer. If negative, length is set as the buffer length minus",
 | 
			
		||||
  "Buffer.shift|param|offset": "number of bytes to shift; use negative value to shift right",
 | 
			
		||||
  "Buffer.shift|param|start": "start offset in buffer. Default is 0.",
 | 
			
		||||
  "Buffer.slice": "Return a copy of a fragment of a buffer.",
 | 
			
		||||
  "Buffer.toHex": "Convert a buffer to its hexadecimal representation.",
 | 
			
		||||
  "Buffer.write": "Write contents of `src` at `dstOffset` in current buffer.",
 | 
			
		||||
  "EventCreationMode": "How to create the event.",
 | 
			
		||||
  "EventCreationMode.CreateAndFire": "MicroBitEvent is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!).",
 | 
			
		||||
@@ -189,6 +190,8 @@
 | 
			
		||||
  "basic.showString|param|text": "the text to scroll on the screen, eg: \"Hello!\"",
 | 
			
		||||
  "control": "Runtime and event utilities.",
 | 
			
		||||
  "control.assert": "If the condition is false, display msg on serial console, and panic with code 098.",
 | 
			
		||||
  "control.createBuffer": "Create a new zero-initialized 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",
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -53,18 +53,17 @@ namespace basic {
 | 
			
		||||
    //% async
 | 
			
		||||
    //% blockId=device_print_message
 | 
			
		||||
    //% parts="ledmatrix"
 | 
			
		||||
    void showString(StringData *text, int interval = 150) {
 | 
			
		||||
    void showString(String text, int interval = 150) {
 | 
			
		||||
      if (interval <= 0)
 | 
			
		||||
        interval = 1;
 | 
			
		||||
      ManagedString s(text);
 | 
			
		||||
      int l = s.length();
 | 
			
		||||
      int l = text ? text->length : 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.print(text->data[0], interval * 5);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -86,7 +85,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -96,18 +95,11 @@ 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
 | 
			
		||||
@@ -115,10 +107,7 @@ namespace basic {
 | 
			
		||||
    //% help=basic/forever weight=55 blockGap=8 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,160 +1,356 @@
 | 
			
		||||
#include "pxt.h"
 | 
			
		||||
#include "pxtbase.h"
 | 
			
		||||
#include <limits.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,
 | 
			
		||||
};
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
//% indexerGet=BufferMethods::getByte indexerSet=BufferMethods::setByte
 | 
			
		||||
namespace BufferMethods {
 | 
			
		||||
    //%
 | 
			
		||||
    int getByte(Buffer buf, int off) {
 | 
			
		||||
        return max(ManagedBuffer(buf).getByte(off), 0);
 | 
			
		||||
//%
 | 
			
		||||
uint8_t *getBytes(Buffer buf) {
 | 
			
		||||
    return buf->data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
int getByte(Buffer buf, int off) {
 | 
			
		||||
    if (buf && 0 <= off && off < buf->length)
 | 
			
		||||
        return buf->data[off];
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
void setByte(Buffer buf, int off, int v) {
 | 
			
		||||
    if (buf && 0 <= off && off < buf->length)
 | 
			
		||||
        buf->data[off] = v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int writeBuffer(Buffer buf, int dstOffset, Buffer src, int srcOffset = 0, int length = -1) {
 | 
			
		||||
    if (length < 0)
 | 
			
		||||
        length = src->length;
 | 
			
		||||
 | 
			
		||||
    if (srcOffset < 0 || dstOffset < 0 || dstOffset > buf->length)
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    length = min(src->length - srcOffset, buf->length - dstOffset);
 | 
			
		||||
 | 
			
		||||
    if (length < 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    if (buf == src) {
 | 
			
		||||
        memmove(buf->data + dstOffset, src->data + srcOffset, length);
 | 
			
		||||
    } else {
 | 
			
		||||
        memcpy(buf->data + dstOffset, src->data + srcOffset, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //%
 | 
			
		||||
    void setByte(Buffer buf, int off, int v) {
 | 
			
		||||
        ManagedBuffer(buf).setByte(off, v);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write a number in specified format in the buffer.
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
void setNumber(Buffer buf, NumberFormat format, int offset, TNumber value) {
 | 
			
		||||
    if (offset < 0)
 | 
			
		||||
        return;
 | 
			
		||||
    setNumberCore(buf->data + offset, buf->length - offset, format, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Read a number in specified format from the buffer.
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
TNumber getNumber(Buffer buf, NumberFormat format, int offset) {
 | 
			
		||||
    if (offset < 0)
 | 
			
		||||
        return fromInt(0);
 | 
			
		||||
    return getNumberCore(buf->data + offset, buf->length - offset, format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 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) {
 | 
			
		||||
    if (offset < 0 || offset > buf->length)
 | 
			
		||||
        return; // DEVICE_INVALID_PARAMETER;
 | 
			
		||||
    if (length < 0)
 | 
			
		||||
        length = buf->length;
 | 
			
		||||
    length = min(length, buf->length - offset);
 | 
			
		||||
    memset(buf->data + offset, value, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return a copy of a fragment of a buffer.
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
Buffer slice(Buffer buf, int offset = 0, int length = -1) {
 | 
			
		||||
    offset = min((int)buf->length, offset);
 | 
			
		||||
    if (length < 0)
 | 
			
		||||
        length = buf->length;
 | 
			
		||||
    length = min(length, buf->length - offset);
 | 
			
		||||
    return mkBuffer(buf->data + offset, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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) {
 | 
			
		||||
    if (length < 0)
 | 
			
		||||
        length = buf->length - start;
 | 
			
		||||
    if (start < 0 || start + length > buf->length || start + length < start || length == 0 ||
 | 
			
		||||
        offset == 0 || offset == INT_MIN)
 | 
			
		||||
        return;
 | 
			
		||||
    if (offset <= -length || offset >= length) {
 | 
			
		||||
        fill(buf, 0);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //%
 | 
			
		||||
    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);
 | 
			
		||||
    uint8_t *data = buf->data + start;
 | 
			
		||||
    if (offset < 0) {
 | 
			
		||||
        offset = -offset;
 | 
			
		||||
        memmove(data + offset, data, length - offset);
 | 
			
		||||
        memset(data, 0, offset);
 | 
			
		||||
    } else {
 | 
			
		||||
        length = length - offset;
 | 
			
		||||
        memmove(data, data + offset, length);
 | 
			
		||||
        memset(data + length, 0, offset);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convert a buffer to its hexadecimal representation.
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
String toHex(Buffer buf) {
 | 
			
		||||
    const char *hex = "0123456789abcdef";
 | 
			
		||||
    auto res = mkString(NULL, buf->length * 2);
 | 
			
		||||
    for (int i = 0; i < buf->length; ++i) {
 | 
			
		||||
        res->data[i << 1] = hex[buf->data[i] >> 4];
 | 
			
		||||
        res->data[(i << 1) + 1] = hex[buf->data[i] & 0xf];
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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) {
 | 
			
		||||
    if (length < 0)
 | 
			
		||||
        length = buf->length - start;
 | 
			
		||||
    if (start < 0 || start + length > buf->length || start + length < start || length == 0 ||
 | 
			
		||||
        offset == 0 || offset == INT_MIN)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (offset < 0)
 | 
			
		||||
        offset += length << 8; // try to make it positive
 | 
			
		||||
    offset %= length;
 | 
			
		||||
    if (offset < 0)
 | 
			
		||||
        offset += length;
 | 
			
		||||
 | 
			
		||||
    uint8_t *data = buf->data + start;
 | 
			
		||||
 | 
			
		||||
    uint8_t *n_first = data + offset;
 | 
			
		||||
    uint8_t *first = data;
 | 
			
		||||
    uint8_t *next = n_first;
 | 
			
		||||
    uint8_t *last = data + length;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Write contents of `src` at `dstOffset` in current buffer.
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
void write(Buffer buf, int dstOffset, Buffer src) {
 | 
			
		||||
    // srcOff and length not supported, we only do up to 4 args :/
 | 
			
		||||
    writeBuffer(buf, dstOffset, src, 0, -1);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace control {
 | 
			
		||||
/**
 | 
			
		||||
 * Create a new zero-initialized buffer.
 | 
			
		||||
 * @param size number of bytes in the buffer
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
Buffer createBuffer(int size) {
 | 
			
		||||
    return mkBuffer(NULL, size);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace pxt {
 | 
			
		||||
static int writeBytes(uint8_t *dst, uint8_t *src, int length, bool swapBytes, int szLeft) {
 | 
			
		||||
    if (szLeft < length) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (swapBytes) {
 | 
			
		||||
        uint8_t *p = dst + length;
 | 
			
		||||
        for (int i = 0; i < length; ++i)
 | 
			
		||||
            *--p = src[i];
 | 
			
		||||
    } else {
 | 
			
		||||
        if (length == 4 && ((uint32_t)dst & 3) == 0)
 | 
			
		||||
            *(uint32_t *)dst = *(uint32_t *)src;
 | 
			
		||||
        else if (length == 2 && ((uint32_t)dst & 1) == 0)
 | 
			
		||||
            *(uint16_t *)dst = *(uint16_t *)src;
 | 
			
		||||
        else
 | 
			
		||||
            memcpy(dst, src, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int readBytes(uint8_t *src, uint8_t *dst, int length, bool swapBytes, int szLeft) {
 | 
			
		||||
    if (szLeft < length) {
 | 
			
		||||
        memset(dst, 0, length);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (swapBytes) {
 | 
			
		||||
        uint8_t *p = src + length;
 | 
			
		||||
        for (int i = 0; i < length; ++i)
 | 
			
		||||
            dst[i] = *--p;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (length == 4 && ((uint32_t)src & 3) == 0)
 | 
			
		||||
            *(uint32_t *)dst = *(uint32_t *)src;
 | 
			
		||||
        else if (length == 2 && ((uint32_t)src & 1) == 0)
 | 
			
		||||
            *(uint16_t *)dst = *(uint16_t *)src;
 | 
			
		||||
        else
 | 
			
		||||
            memcpy(dst, src, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setNumberCore(uint8_t *buf, int szLeft, NumberFormat format, TNumber value) {
 | 
			
		||||
    int8_t i8;
 | 
			
		||||
    uint8_t u8;
 | 
			
		||||
    int16_t i16;
 | 
			
		||||
    uint16_t u16;
 | 
			
		||||
    int32_t i32;
 | 
			
		||||
    uint32_t u32;
 | 
			
		||||
    float f32;
 | 
			
		||||
    double f64;
 | 
			
		||||
 | 
			
		||||
// Assume little endian
 | 
			
		||||
#define WRITEBYTES(isz, swap, toInt)                                                               \
 | 
			
		||||
    isz = toInt(value);                                                                            \
 | 
			
		||||
    writeBytes(buf, (uint8_t *)&isz, sizeof(isz), swap, szLeft);                                   \
 | 
			
		||||
    break
 | 
			
		||||
 | 
			
		||||
    switch (format) {
 | 
			
		||||
    case NumberFormat::Int8LE:
 | 
			
		||||
        WRITEBYTES(i8, false, toInt);
 | 
			
		||||
    case NumberFormat::UInt8LE:
 | 
			
		||||
        WRITEBYTES(u8, false, toInt);
 | 
			
		||||
    case NumberFormat::Int16LE:
 | 
			
		||||
        WRITEBYTES(i16, false, toInt);
 | 
			
		||||
    case NumberFormat::UInt16LE:
 | 
			
		||||
        WRITEBYTES(u16, false, toInt);
 | 
			
		||||
    case NumberFormat::Int32LE:
 | 
			
		||||
        WRITEBYTES(i32, false, toInt);
 | 
			
		||||
    case NumberFormat::UInt32LE:
 | 
			
		||||
        WRITEBYTES(u32, false, toUInt);
 | 
			
		||||
 | 
			
		||||
    case NumberFormat::Int8BE:
 | 
			
		||||
        WRITEBYTES(i8, true, toInt);
 | 
			
		||||
    case NumberFormat::UInt8BE:
 | 
			
		||||
        WRITEBYTES(u8, true, toInt);
 | 
			
		||||
    case NumberFormat::Int16BE:
 | 
			
		||||
        WRITEBYTES(i16, true, toInt);
 | 
			
		||||
    case NumberFormat::UInt16BE:
 | 
			
		||||
        WRITEBYTES(u16, true, toInt);
 | 
			
		||||
    case NumberFormat::Int32BE:
 | 
			
		||||
        WRITEBYTES(i32, true, toInt);
 | 
			
		||||
    case NumberFormat::UInt32BE:
 | 
			
		||||
        WRITEBYTES(u32, true, toUInt);
 | 
			
		||||
 | 
			
		||||
    case NumberFormat::Float32LE:
 | 
			
		||||
        WRITEBYTES(f32, false, toFloat);
 | 
			
		||||
    case NumberFormat::Float32BE:
 | 
			
		||||
        WRITEBYTES(f32, true, toFloat);
 | 
			
		||||
    case NumberFormat::Float64LE:
 | 
			
		||||
        WRITEBYTES(f64, false, toDouble);
 | 
			
		||||
    case NumberFormat::Float64BE:
 | 
			
		||||
        WRITEBYTES(f64, true, toDouble);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TNumber getNumberCore(uint8_t *buf, int szLeft, NumberFormat format) {
 | 
			
		||||
    int8_t i8;
 | 
			
		||||
    uint8_t u8;
 | 
			
		||||
    int16_t i16;
 | 
			
		||||
    uint16_t u16;
 | 
			
		||||
    int32_t i32;
 | 
			
		||||
    uint32_t u32;
 | 
			
		||||
    float f32;
 | 
			
		||||
    double f64;
 | 
			
		||||
 | 
			
		||||
// Assume little endian
 | 
			
		||||
#define READBYTES(isz, swap, conv)                                                                 \
 | 
			
		||||
    readBytes(buf, (uint8_t *)&isz, sizeof(isz), swap, szLeft);                                    \
 | 
			
		||||
    return conv(isz)
 | 
			
		||||
 | 
			
		||||
    switch (format) {
 | 
			
		||||
    case NumberFormat::Int8LE:
 | 
			
		||||
        READBYTES(i8, false, fromInt);
 | 
			
		||||
    case NumberFormat::UInt8LE:
 | 
			
		||||
        READBYTES(u8, false, fromInt);
 | 
			
		||||
    case NumberFormat::Int16LE:
 | 
			
		||||
        READBYTES(i16, false, fromInt);
 | 
			
		||||
    case NumberFormat::UInt16LE:
 | 
			
		||||
        READBYTES(u16, false, fromInt);
 | 
			
		||||
    case NumberFormat::Int32LE:
 | 
			
		||||
        READBYTES(i32, false, fromInt);
 | 
			
		||||
    case NumberFormat::UInt32LE:
 | 
			
		||||
        READBYTES(u32, false, fromUInt);
 | 
			
		||||
 | 
			
		||||
    case NumberFormat::Int8BE:
 | 
			
		||||
        READBYTES(i8, true, fromInt);
 | 
			
		||||
    case NumberFormat::UInt8BE:
 | 
			
		||||
        READBYTES(u8, true, fromInt);
 | 
			
		||||
    case NumberFormat::Int16BE:
 | 
			
		||||
        READBYTES(i16, true, fromInt);
 | 
			
		||||
    case NumberFormat::UInt16BE:
 | 
			
		||||
        READBYTES(u16, true, fromInt);
 | 
			
		||||
    case NumberFormat::Int32BE:
 | 
			
		||||
        READBYTES(i32, true, fromInt);
 | 
			
		||||
    case NumberFormat::UInt32BE:
 | 
			
		||||
        READBYTES(u32, true, fromUInt);
 | 
			
		||||
 | 
			
		||||
    case NumberFormat::Float32LE:
 | 
			
		||||
        READBYTES(f32, false, fromFloat);
 | 
			
		||||
    case NumberFormat::Float32BE:
 | 
			
		||||
        READBYTES(f32, true, fromFloat);
 | 
			
		||||
    case NumberFormat::Float64LE:
 | 
			
		||||
        READBYTES(f64, false, fromDouble);
 | 
			
		||||
    case NumberFormat::Float64BE:
 | 
			
		||||
        READBYTES(f64, true, fromDouble);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										234
									
								
								libs/core/codal.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								libs/core/codal.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,234 @@
 | 
			
		||||
#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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace pxt {
 | 
			
		||||
 | 
			
		||||
MicroBit uBit;
 | 
			
		||||
MicroBitEvent lastEvent;
 | 
			
		||||
 | 
			
		||||
void platform_init() {}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    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);
 | 
			
		||||
        create_fiber(forever_stub, (void *)a);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void runInParallel(Action a) {
 | 
			
		||||
    if (a != 0) {
 | 
			
		||||
        incr(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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace pxt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -220,7 +220,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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -290,8 +290,8 @@ namespace control {
 | 
			
		||||
     */
 | 
			
		||||
    //% 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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1452
									
								
								libs/core/core.cpp
									
									
									
									
									
								
							
							
						
						
									
										1452
									
								
								libs/core/core.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										46
									
								
								libs/core/enums.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								libs/core/enums.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,35 @@
 | 
			
		||||
// 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 ValType {
 | 
			
		||||
    Undefined = 0,
 | 
			
		||||
    Boolean = 1,
 | 
			
		||||
    Number = 2,
 | 
			
		||||
    String = 3,
 | 
			
		||||
    Object = 4,
 | 
			
		||||
    Function = 5,
 | 
			
		||||
    }
 | 
			
		||||
declare namespace images {
 | 
			
		||||
}
 | 
			
		||||
declare namespace basic {
 | 
			
		||||
@@ -536,19 +567,4 @@ declare namespace led {
 | 
			
		||||
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.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,156 +1,178 @@
 | 
			
		||||
#include "pxt.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Creation, manipulation and display of LED images.
 | 
			
		||||
*/
 | 
			
		||||
//% color=#5C2D91 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();
 | 
			
		||||
    }
 | 
			
		||||
PXT_VTABLE_BEGIN(RefMImage, 0, 0)
 | 
			
		||||
PXT_VTABLE_END
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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);
 | 
			
		||||
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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creation, manipulation and display of LED images.
 | 
			
		||||
 */
 | 
			
		||||
//% color=#5C2D91 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 new 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);
 | 
			
		||||
    }
 | 
			
		||||
/**
 | 
			
		||||
 * 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|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);
 | 
			
		||||
    }
 | 
			
		||||
/**
 | 
			
		||||
 * 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->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);
 | 
			
		||||
    }
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
    }
 | 
			
		||||
/**
 | 
			
		||||
 * 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->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 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) {
 | 
			
		||||
    i->makeWritable();
 | 
			
		||||
    MicroBitImage(i->img).setPixelValue(x, y, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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->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 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 height in rows (always 5)
 | 
			
		||||
 */
 | 
			
		||||
//%
 | 
			
		||||
int height(Image i) {
 | 
			
		||||
    return i->img->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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the width in columns
 | 
			
		||||
     */
 | 
			
		||||
    //% help=functions/width
 | 
			
		||||
    int width(Image i) {
 | 
			
		||||
        return i->width;
 | 
			
		||||
    }
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
}
 | 
			
		||||
} // namespace ImageMethods
 | 
			
		||||
@@ -139,7 +139,10 @@ namespace led {
 | 
			
		||||
    //% help=led/screenshot
 | 
			
		||||
    //% parts="ledmatrix"
 | 
			
		||||
    Image screenshot() {
 | 
			
		||||
      return uBit.display.screenShot().leakData();
 | 
			
		||||
        auto d = uBit.display.screenShot().leakData();
 | 
			
		||||
        auto r = new RefMImage(d);
 | 
			
		||||
        d->decr();
 | 
			
		||||
        return r;
 | 
			
		||||
        /*
 | 
			
		||||
        let Image img;
 | 
			
		||||
        img = image.createImage("");
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,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;
 | 
			
		||||
@@ -109,6 +112,7 @@ MicroBitPin *getPin(int id) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // pxt
 | 
			
		||||
 | 
			
		||||
namespace pins {
 | 
			
		||||
    #define PINOP(op) \
 | 
			
		||||
@@ -359,7 +363,7 @@ namespace pins {
 | 
			
		||||
    //%
 | 
			
		||||
    Buffer createBuffer(int size)
 | 
			
		||||
    {
 | 
			
		||||
        return ManagedBuffer(size).leakData();
 | 
			
		||||
        return mkBuffer(NULL, size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -369,7 +373,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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -379,7 +383,7 @@ namespace pins {
 | 
			
		||||
    //%
 | 
			
		||||
    void i2cWriteBuffer(int address, Buffer buf, bool repeat = false)
 | 
			
		||||
    {
 | 
			
		||||
      uBit.i2c.write(address << 1, (char*)buf->payload, buf->length, repeat);
 | 
			
		||||
      uBit.i2c.write(address << 1, (char*)buf->data, buf->length, repeat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SPI* spi = NULL;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1063
									
								
								libs/core/pxt.cpp
									
									
									
									
									
								
							
							
						
						
									
										1063
									
								
								libs/core/pxt.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										379
									
								
								libs/core/pxt.h
									
									
									
									
									
								
							
							
						
						
									
										379
									
								
								libs/core/pxt.h
									
									
									
									
									
								
							@@ -5,375 +5,54 @@
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    inline VTable *getVTable() {
 | 
			
		||||
      return (VTable*)(vtable << vtableShift);
 | 
			
		||||
    }
 | 
			
		||||
#define MSTR(s) ManagedString((s)->data, (s)->length)
 | 
			
		||||
 | 
			
		||||
    void destroy();
 | 
			
		||||
    void print();
 | 
			
		||||
static inline String PSTR(ManagedString s) {
 | 
			
		||||
    return mkString(s.toCharArray(), s.length());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
    }
 | 
			
		||||
typedef uint32_t ImageLiteral_;
 | 
			
		||||
 | 
			
		||||
    // 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;
 | 
			
		||||
    }
 | 
			
		||||
static inline ImageData *imageBytes(ImageLiteral_ lit) {
 | 
			
		||||
    return (ImageData*)ptrOfLiteral(lit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    inline void unref()
 | 
			
		||||
    {
 | 
			
		||||
      //printf("DECR "); this->print();
 | 
			
		||||
      check(refcnt > 0, ERR_REF_DELETED);
 | 
			
		||||
      refcnt -= 2;
 | 
			
		||||
      if (refcnt == 0) {
 | 
			
		||||
        destroy();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
typedef RefMImage *Image;
 | 
			
		||||
 | 
			
		||||
  class Segment {
 | 
			
		||||
  private:    
 | 
			
		||||
      uint32_t* data;
 | 
			
		||||
      uint16_t length;
 | 
			
		||||
      uint16_t size;
 | 
			
		||||
extern MicroBit uBit;
 | 
			
		||||
extern MicroBitEvent lastEvent;
 | 
			
		||||
 | 
			
		||||
      static const uint16_t MaxSize = 0xFFFF;
 | 
			
		||||
      static const uint32_t DefaultValue = 0x0;
 | 
			
		||||
MicroBitPin *getPin(int id);
 | 
			
		||||
 | 
			
		||||
      static uint16_t growthFactor(uint16_t size);      
 | 
			
		||||
      void growByMin(uint16_t minSize);
 | 
			
		||||
      void growBy(uint16_t newSize);
 | 
			
		||||
      void ensure(uint16_t newSize);
 | 
			
		||||
static inline int min_(int a, int b) {
 | 
			
		||||
    if (a < b) return a;
 | 
			
		||||
    else return b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
      Segment() : data (nullptr), length(0), size(0) {};
 | 
			
		||||
static inline int max_(int a, int b) {
 | 
			
		||||
    if (a > b) return a;
 | 
			
		||||
    else return b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
      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();
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using namespace pxt;
 | 
			
		||||
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,
 | 
			
		||||
 | 
			
		||||
#define PXT_SHIMS_END }; }
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wpmf-conversions"
 | 
			
		||||
 | 
			
		||||
#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,
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_END } };
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_INIT(classname) \
 | 
			
		||||
  RefObject(PXT_VTABLE_TO_INT(&classname ## _vtable))
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_CTOR(classname) \
 | 
			
		||||
  PXT_VTABLE_BEGIN(classname, 0, 0) PXT_VTABLE_END \
 | 
			
		||||
  classname::classname() : PXT_VTABLE_INIT(classname)
 | 
			
		||||
#define DEVICE_EVT_ANY 0
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,10 @@
 | 
			
		||||
    "installedVersion": "tsmdvf",
 | 
			
		||||
    "files": [
 | 
			
		||||
        "README.md",
 | 
			
		||||
        "ManagedBuffer.cpp",
 | 
			
		||||
        "ManagedBuffer.h",
 | 
			
		||||
        "pxt.cpp",
 | 
			
		||||
        "pxt.h",
 | 
			
		||||
        "pxtbase.h",
 | 
			
		||||
        "pxtcore.h",
 | 
			
		||||
        "dal.d.ts",
 | 
			
		||||
        "enums.d.ts",
 | 
			
		||||
        "shims.d.ts",
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
        "core.cpp",
 | 
			
		||||
        "pxt-helpers.ts",
 | 
			
		||||
        "helpers.ts",
 | 
			
		||||
        "codal.cpp",
 | 
			
		||||
        "images.cpp",
 | 
			
		||||
        "basic.cpp",
 | 
			
		||||
        "icons.ts",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										701
									
								
								libs/core/pxtbase.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										701
									
								
								libs/core/pxtbase.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,701 @@
 | 
			
		||||
#ifndef __PXTBASE_H
 | 
			
		||||
#define __PXTBASE_H
 | 
			
		||||
 | 
			
		||||
//#define PXT_MEMLEAK_DEBUG 1
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wformat"
 | 
			
		||||
#pragma GCC diagnostic ignored "-Warray-bounds"
 | 
			
		||||
 | 
			
		||||
// needed for gcc6; not sure why
 | 
			
		||||
#undef min
 | 
			
		||||
#undef max
 | 
			
		||||
 | 
			
		||||
#define NOLOG(...)                                                                                 \
 | 
			
		||||
    do {                                                                                           \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
#define MEMDBG_ENABLED 0
 | 
			
		||||
#define MEMDBG NOLOG
 | 
			
		||||
 | 
			
		||||
#include "pxtconfig.h"
 | 
			
		||||
 | 
			
		||||
#define intcheck(...) check(__VA_ARGS__)
 | 
			
		||||
//#define intcheck(...) do {} while (0)
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include <new>
 | 
			
		||||
 | 
			
		||||
#ifdef PXT_MEMLEAK_DEBUG
 | 
			
		||||
#include <set>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "pxtcore.h"
 | 
			
		||||
 | 
			
		||||
#ifndef PXT_VTABLE_SHIFT
 | 
			
		||||
#define PXT_VTABLE_SHIFT 2
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define CONCAT_1(a, b) a##b
 | 
			
		||||
#define CONCAT_0(a, b) CONCAT_1(a, b)
 | 
			
		||||
#define STATIC_ASSERT(e) enum { CONCAT_0(_static_assert_, __LINE__) = 1 / ((e) ? 1 : 0) };
 | 
			
		||||
 | 
			
		||||
#ifndef ramint_t
 | 
			
		||||
// this type limits size of arrays
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#define ramint_t uint32_t
 | 
			
		||||
#else
 | 
			
		||||
#define ramint_t uint16_t
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
inline void *operator new(size_t, void *p) {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
inline void *operator new[](size_t, void *p) {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace pxt {
 | 
			
		||||
 | 
			
		||||
template <typename T> inline const T &max(const T &a, const T &b) {
 | 
			
		||||
    if (a < b)
 | 
			
		||||
        return b;
 | 
			
		||||
    return a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T> inline const T &min(const T &a, const T &b) {
 | 
			
		||||
    if (a < b)
 | 
			
		||||
        return a;
 | 
			
		||||
    return b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T> inline void swap(T &a, T &b) {
 | 
			
		||||
    T tmp = a;
 | 
			
		||||
    a = b;
 | 
			
		||||
    b = tmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Tagged values (assume 4 bytes for now, Cortex-M0)
 | 
			
		||||
//
 | 
			
		||||
struct TValueStruct {};
 | 
			
		||||
typedef TValueStruct *TValue;
 | 
			
		||||
 | 
			
		||||
typedef TValue TNumber;
 | 
			
		||||
typedef TValue Action;
 | 
			
		||||
typedef TValue ImageLiteral;
 | 
			
		||||
 | 
			
		||||
// To be implemented by the target
 | 
			
		||||
extern "C" void target_panic(int error_code);
 | 
			
		||||
extern "C" void target_reset();
 | 
			
		||||
void sleep_ms(unsigned ms);
 | 
			
		||||
void sleep_us(uint64_t us);
 | 
			
		||||
void releaseFiber();
 | 
			
		||||
int current_time_ms();
 | 
			
		||||
void initRuntime();
 | 
			
		||||
void sendSerial(const char *data, int len);
 | 
			
		||||
int getSerialNumber();
 | 
			
		||||
void registerWithDal(int id, int event, Action a, int flags = 16); // EVENT_LISTENER_DEFAULT_FLAGS
 | 
			
		||||
void runInParallel(Action a);
 | 
			
		||||
void runForever(Action a);
 | 
			
		||||
void waitForEvent(int id, int event);
 | 
			
		||||
//%
 | 
			
		||||
unsigned afterProgramPage();
 | 
			
		||||
//%
 | 
			
		||||
void dumpDmesg();
 | 
			
		||||
 | 
			
		||||
// also defined DMESG macro
 | 
			
		||||
// end
 | 
			
		||||
 | 
			
		||||
#define TAGGED_SPECIAL(n) (TValue)(void *)((n << 2) | 2)
 | 
			
		||||
#define TAG_FALSE TAGGED_SPECIAL(2)
 | 
			
		||||
#define TAG_TRUE TAGGED_SPECIAL(16)
 | 
			
		||||
#define TAG_UNDEFINED (TValue)0
 | 
			
		||||
#define TAG_NULL TAGGED_SPECIAL(1)
 | 
			
		||||
#define TAG_NUMBER(n) (TNumber)(void *)((n << 1) | 1)
 | 
			
		||||
 | 
			
		||||
inline bool isTagged(TValue v) {
 | 
			
		||||
    return ((intptr_t)v & 3) || !v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool isNumber(TValue v) {
 | 
			
		||||
    return (intptr_t)v & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool isSpecial(TValue v) {
 | 
			
		||||
    return (intptr_t)v & 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool bothNumbers(TValue a, TValue b) {
 | 
			
		||||
    return (intptr_t)a & (intptr_t)b & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int numValue(TValue n) {
 | 
			
		||||
    return (intptr_t)n >> 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef PXT_BOX_DEBUG
 | 
			
		||||
inline bool canBeTagged(int) {
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
inline bool canBeTagged(int v) {
 | 
			
		||||
    return (v << 1) >> 1 == v;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    ERR_INVALID_BINARY_HEADER = 5,
 | 
			
		||||
    ERR_OUT_OF_BOUNDS = 8,
 | 
			
		||||
    ERR_REF_DELETED = 7,
 | 
			
		||||
    ERR_SIZE = 9,
 | 
			
		||||
} PXT_ERROR;
 | 
			
		||||
 | 
			
		||||
extern const unsigned functionsAndBytecode[];
 | 
			
		||||
extern TValue *globals;
 | 
			
		||||
extern uint16_t *bytecode;
 | 
			
		||||
class RefRecord;
 | 
			
		||||
 | 
			
		||||
// Utility functions
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
TValue runAction3(Action a, TValue arg0, TValue arg1, TValue arg2);
 | 
			
		||||
//%
 | 
			
		||||
TValue runAction2(Action a, TValue arg0, TValue arg1);
 | 
			
		||||
//%
 | 
			
		||||
TValue runAction1(Action a, TValue arg0);
 | 
			
		||||
//%
 | 
			
		||||
TValue runAction0(Action a);
 | 
			
		||||
//%
 | 
			
		||||
Action mkAction(int reflen, int totallen, int startptr);
 | 
			
		||||
// allocate [sz] words and clear them
 | 
			
		||||
//%
 | 
			
		||||
unsigned *allocate(ramint_t sz);
 | 
			
		||||
//%
 | 
			
		||||
int templateHash();
 | 
			
		||||
//%
 | 
			
		||||
int programHash();
 | 
			
		||||
//%
 | 
			
		||||
unsigned programSize();
 | 
			
		||||
//%
 | 
			
		||||
int getNumGlobals();
 | 
			
		||||
//%
 | 
			
		||||
RefRecord *mkClassInstance(int vtableOffset);
 | 
			
		||||
//%
 | 
			
		||||
void debugMemLeaks();
 | 
			
		||||
//%
 | 
			
		||||
void anyPrint(TValue v);
 | 
			
		||||
 | 
			
		||||
int getConfig(int key, int defl = -1);
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
int toInt(TNumber v);
 | 
			
		||||
//%
 | 
			
		||||
unsigned toUInt(TNumber v);
 | 
			
		||||
//%
 | 
			
		||||
double toDouble(TNumber v);
 | 
			
		||||
//%
 | 
			
		||||
float toFloat(TNumber v);
 | 
			
		||||
//%
 | 
			
		||||
TNumber fromDouble(double r);
 | 
			
		||||
//%
 | 
			
		||||
TNumber fromFloat(float r);
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
TNumber fromInt(int v);
 | 
			
		||||
//%
 | 
			
		||||
TNumber fromUInt(unsigned v);
 | 
			
		||||
//%
 | 
			
		||||
TValue fromBool(bool v);
 | 
			
		||||
//%
 | 
			
		||||
bool eq_bool(TValue a, TValue b);
 | 
			
		||||
//%
 | 
			
		||||
bool eqq_bool(TValue a, TValue b);
 | 
			
		||||
 | 
			
		||||
void error(PXT_ERROR code, int subcode = 0);
 | 
			
		||||
void exec_binary(unsigned *pc);
 | 
			
		||||
void start();
 | 
			
		||||
 | 
			
		||||
struct HandlerBinding {
 | 
			
		||||
    HandlerBinding *next;
 | 
			
		||||
    int source;
 | 
			
		||||
    int value;
 | 
			
		||||
    Action action;
 | 
			
		||||
};
 | 
			
		||||
HandlerBinding *findBinding(int source, int value);
 | 
			
		||||
void setBinding(int source, int value, Action act);
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
//%
 | 
			
		||||
TValue incr(TValue e);
 | 
			
		||||
//%
 | 
			
		||||
void decr(TValue e);
 | 
			
		||||
 | 
			
		||||
class RefObject;
 | 
			
		||||
 | 
			
		||||
static inline RefObject *incrRC(RefObject *r) {
 | 
			
		||||
    return (RefObject *)incr((TValue)r);
 | 
			
		||||
}
 | 
			
		||||
static inline void decrRC(RefObject *r) {
 | 
			
		||||
    decr((TValue)r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void *ptrOfLiteral(int offset) {
 | 
			
		||||
    return &bytecode[offset];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Checks if object is ref-counted, and has a custom PXT vtable in front
 | 
			
		||||
// TODO
 | 
			
		||||
inline bool isRefCounted(TValue e) {
 | 
			
		||||
    return !isTagged(e) && (*((unsigned *)e) & 1) == 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void check(int cond, PXT_ERROR code, int subcode = 0) {
 | 
			
		||||
    if (!cond)
 | 
			
		||||
        error(code, subcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void oops() {
 | 
			
		||||
    target_panic(47);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class RefObject;
 | 
			
		||||
#ifdef PXT_MEMLEAK_DEBUG
 | 
			
		||||
extern std::set<TValue> allptrs;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef void (*RefObjectMethod)(RefObject *self);
 | 
			
		||||
typedef void *PVoid;
 | 
			
		||||
typedef void **PPVoid;
 | 
			
		||||
 | 
			
		||||
typedef void *Object_;
 | 
			
		||||
 | 
			
		||||
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 = PXT_VTABLE_SHIFT;
 | 
			
		||||
 | 
			
		||||
// A base abstract class for ref-counted objects.
 | 
			
		||||
class RefObject {
 | 
			
		||||
  public:
 | 
			
		||||
    uint16_t refcnt;
 | 
			
		||||
    uint16_t vtable;
 | 
			
		||||
 | 
			
		||||
    RefObject(uint16_t vt) {
 | 
			
		||||
        refcnt = 3;
 | 
			
		||||
        vtable = vt;
 | 
			
		||||
#ifdef PXT_MEMLEAK_DEBUG
 | 
			
		||||
        allptrs.insert((TValue)this);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void destroyVT();
 | 
			
		||||
    void printVT();
 | 
			
		||||
 | 
			
		||||
    // Call to disable pointer tracking on the current instance (in destructor or some other hack)
 | 
			
		||||
    inline void untrack() {
 | 
			
		||||
#ifdef PXT_MEMLEAK_DEBUG
 | 
			
		||||
        allptrs.erase((TValue)this);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline bool isReadOnly() { return refcnt == 0xffff; }
 | 
			
		||||
 | 
			
		||||
    // Increment/decrement the ref-count. Decrementing to zero deletes the current object.
 | 
			
		||||
    inline void ref() {
 | 
			
		||||
        if (isReadOnly())
 | 
			
		||||
            return;
 | 
			
		||||
        check(refcnt > 1, ERR_REF_DELETED);
 | 
			
		||||
        // DMESG("INCR "); this->print();
 | 
			
		||||
        refcnt += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void unref() {
 | 
			
		||||
        if (isReadOnly())
 | 
			
		||||
            return;
 | 
			
		||||
        check(refcnt > 1, ERR_REF_DELETED);
 | 
			
		||||
        check((refcnt & 1), ERR_REF_DELETED);
 | 
			
		||||
        // DMESG("DECR "); this->print();
 | 
			
		||||
        refcnt -= 2;
 | 
			
		||||
        if (refcnt == 1) {
 | 
			
		||||
            untrack();
 | 
			
		||||
            destroyVT();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Segment {
 | 
			
		||||
  private:
 | 
			
		||||
    TValue *data;
 | 
			
		||||
    ramint_t length;
 | 
			
		||||
    ramint_t size;
 | 
			
		||||
 | 
			
		||||
    // this just gives max value of ramint_t
 | 
			
		||||
    static constexpr ramint_t MaxSize = (((1U << (8 * sizeof(ramint_t) - 1)) - 1) << 1) + 1;
 | 
			
		||||
    static constexpr TValue DefaultValue = TAG_UNDEFINED;
 | 
			
		||||
 | 
			
		||||
    static ramint_t growthFactor(ramint_t size);
 | 
			
		||||
    void growByMin(ramint_t minSize);
 | 
			
		||||
    void growBy(ramint_t newSize);
 | 
			
		||||
    void ensure(ramint_t newSize);
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    Segment() : data(nullptr), length(0), size(0){};
 | 
			
		||||
 | 
			
		||||
    TValue get(unsigned i);
 | 
			
		||||
    void set(unsigned i, TValue value);
 | 
			
		||||
    void setRef(unsigned i, TValue value);
 | 
			
		||||
 | 
			
		||||
    unsigned getLength() { return length; };
 | 
			
		||||
    void setLength(unsigned newLength);
 | 
			
		||||
    void resize(unsigned newLength) { setLength(newLength); }
 | 
			
		||||
 | 
			
		||||
    void push(TValue value);
 | 
			
		||||
    TValue pop();
 | 
			
		||||
 | 
			
		||||
    TValue remove(unsigned i);
 | 
			
		||||
    void insert(unsigned i, TValue value);
 | 
			
		||||
 | 
			
		||||
    bool isValidIndex(unsigned 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:
 | 
			
		||||
    RefCollection();
 | 
			
		||||
 | 
			
		||||
    static void destroy(RefCollection *coll);
 | 
			
		||||
    static void print(RefCollection *coll);
 | 
			
		||||
 | 
			
		||||
    unsigned length() { return head.getLength(); }
 | 
			
		||||
    void setLength(unsigned newLength) { head.setLength(newLength); }
 | 
			
		||||
 | 
			
		||||
    void push(TValue x);
 | 
			
		||||
    TValue pop();
 | 
			
		||||
    TValue getAt(int i);
 | 
			
		||||
    void setAt(int i, TValue x);
 | 
			
		||||
    // removes the element at index i and shifts the other elements left
 | 
			
		||||
    TValue removeAt(int i);
 | 
			
		||||
    // inserts the element at index i and moves the other elements right.
 | 
			
		||||
    void insertAt(int i, TValue x);
 | 
			
		||||
 | 
			
		||||
    int indexOf(TValue x, int start);
 | 
			
		||||
    bool removeElement(TValue x);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class RefMap : public RefObject {
 | 
			
		||||
  public:
 | 
			
		||||
    Segment keys;
 | 
			
		||||
    Segment values;
 | 
			
		||||
 | 
			
		||||
    RefMap();
 | 
			
		||||
    static void destroy(RefMap *map);
 | 
			
		||||
    static void print(RefMap *map);
 | 
			
		||||
    int findIdx(unsigned 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.
 | 
			
		||||
    TValue fields[];
 | 
			
		||||
 | 
			
		||||
    RefRecord(uint16_t v) : RefObject(v) {}
 | 
			
		||||
 | 
			
		||||
    TValue ld(int idx);
 | 
			
		||||
    TValue ldref(int idx);
 | 
			
		||||
    void st(int idx, TValue v);
 | 
			
		||||
    void stref(int idx, TValue v);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//%
 | 
			
		||||
VTable *getVTable(RefObject *r);
 | 
			
		||||
 | 
			
		||||
// these are needed when constructing vtables for user-defined classes
 | 
			
		||||
//%
 | 
			
		||||
void RefRecord_destroy(RefRecord *r);
 | 
			
		||||
//%
 | 
			
		||||
void RefRecord_print(RefRecord *r);
 | 
			
		||||
 | 
			
		||||
class RefAction;
 | 
			
		||||
typedef TValue (*ActionCB)(TValue *captured, TValue arg0, TValue arg1, TValue arg2);
 | 
			
		||||
 | 
			
		||||
// Ref-counted function 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
 | 
			
		||||
    TValue fields[];
 | 
			
		||||
 | 
			
		||||
    static void destroy(RefAction *act);
 | 
			
		||||
    static void print(RefAction *act);
 | 
			
		||||
 | 
			
		||||
    RefAction();
 | 
			
		||||
 | 
			
		||||
    inline void stCore(int idx, TValue v) {
 | 
			
		||||
        // DMESG("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 TValue runCore(TValue arg0, TValue arg1,
 | 
			
		||||
                          TValue arg2) // internal; use runAction*() functions
 | 
			
		||||
    {
 | 
			
		||||
        this->ref();
 | 
			
		||||
        TValue 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:
 | 
			
		||||
    TValue v;
 | 
			
		||||
    static void destroy(RefLocal *l);
 | 
			
		||||
    static void print(RefLocal *l);
 | 
			
		||||
    RefLocal();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class RefRefLocal : public RefObject {
 | 
			
		||||
  public:
 | 
			
		||||
    TValue v;
 | 
			
		||||
    static void destroy(RefRefLocal *l);
 | 
			
		||||
    static void print(RefRefLocal *l);
 | 
			
		||||
    RefRefLocal();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef int color;
 | 
			
		||||
 | 
			
		||||
// note: this is hardcoded in PXT (hexfile.ts)
 | 
			
		||||
 | 
			
		||||
#define PXT_REF_TAG_STRING 1
 | 
			
		||||
#define PXT_REF_TAG_BUFFER 2
 | 
			
		||||
#define PXT_REF_TAG_IMAGE 3
 | 
			
		||||
#define PXT_REF_TAG_NUMBER 32
 | 
			
		||||
#define PXT_REF_TAG_ACTION 33
 | 
			
		||||
 | 
			
		||||
class BoxedNumber : public RefObject {
 | 
			
		||||
  public:
 | 
			
		||||
    double num;
 | 
			
		||||
    BoxedNumber() : RefObject(PXT_REF_TAG_NUMBER) {}
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
class BoxedString : public RefObject {
 | 
			
		||||
  public:
 | 
			
		||||
    uint16_t length;
 | 
			
		||||
    char data[0];
 | 
			
		||||
    BoxedString() : RefObject(PXT_REF_TAG_STRING) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BoxedBuffer : public RefObject {
 | 
			
		||||
  public:
 | 
			
		||||
    // data needs to be word-aligned, so we use 32 bits for length
 | 
			
		||||
    int length;
 | 
			
		||||
    uint8_t data[0];
 | 
			
		||||
    BoxedBuffer() : RefObject(PXT_REF_TAG_BUFFER) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// the first byte of data indicates the format - currently 0xE1 or 0xE4 to 1 or 4 bit bitmaps
 | 
			
		||||
// second byte indicates width in pixels
 | 
			
		||||
// third byte indicates the height (which should also match the size of the buffer)
 | 
			
		||||
// just like ordinary buffers, these can be layed out in flash
 | 
			
		||||
class RefImage : public RefObject {
 | 
			
		||||
    uintptr_t _buffer;
 | 
			
		||||
    uint8_t _data[0];
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    RefImage(BoxedBuffer *buf);
 | 
			
		||||
    RefImage(uint32_t sz);
 | 
			
		||||
 | 
			
		||||
    bool hasBuffer() { return !(_buffer & 1); }
 | 
			
		||||
    BoxedBuffer *buffer() { return hasBuffer() ? (BoxedBuffer *)_buffer : NULL; }
 | 
			
		||||
    void setBuffer(BoxedBuffer *b);
 | 
			
		||||
    bool isDirty() { return (_buffer & 3) == 3; }
 | 
			
		||||
    void clearDirty() { if (isDirty()) _buffer &= ~2; }
 | 
			
		||||
 | 
			
		||||
    uint8_t *data() { return hasBuffer() ? buffer()->data : _data; }
 | 
			
		||||
    int length() { return hasBuffer() ? buffer()->length : (_buffer >> 2); }
 | 
			
		||||
    int pixLength() { return length() - 4; }
 | 
			
		||||
 | 
			
		||||
    int height();
 | 
			
		||||
    int width();
 | 
			
		||||
    int byteHeight();
 | 
			
		||||
    int wordHeight();
 | 
			
		||||
    int bpp();
 | 
			
		||||
 | 
			
		||||
    bool hasPadding() { return (height() & 0x1f) != 0; }
 | 
			
		||||
 | 
			
		||||
    uint8_t *pix() { return data() + 4; }
 | 
			
		||||
    uint8_t *pix(int x, int y);
 | 
			
		||||
    uint8_t fillMask(color c);
 | 
			
		||||
    bool inRange(int x, int y);
 | 
			
		||||
    void clamp(int *x, int *y);
 | 
			
		||||
    void makeWritable();
 | 
			
		||||
 | 
			
		||||
    static void destroy(RefImage *t);
 | 
			
		||||
    static void print(RefImage *t);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RefImage *mkImage(int w, int h, int bpp);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef BoxedBuffer *Buffer;
 | 
			
		||||
typedef BoxedString *String;
 | 
			
		||||
typedef RefImage *Image_;
 | 
			
		||||
 | 
			
		||||
// keep in sync with github/pxt/pxtsim/libgeneric.ts
 | 
			
		||||
enum class NumberFormat {
 | 
			
		||||
    Int8LE = 1,
 | 
			
		||||
    UInt8LE,
 | 
			
		||||
    Int16LE,
 | 
			
		||||
    UInt16LE,
 | 
			
		||||
    Int32LE,
 | 
			
		||||
    Int8BE,
 | 
			
		||||
    UInt8BE,
 | 
			
		||||
    Int16BE,
 | 
			
		||||
    UInt16BE,
 | 
			
		||||
    Int32BE,
 | 
			
		||||
 | 
			
		||||
    UInt32LE,
 | 
			
		||||
    UInt32BE,
 | 
			
		||||
    Float32LE,
 | 
			
		||||
    Float64LE,
 | 
			
		||||
    Float32BE,
 | 
			
		||||
    Float64BE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// data can be NULL in both cases
 | 
			
		||||
String mkString(const char *data, int len = -1);
 | 
			
		||||
Buffer mkBuffer(const uint8_t *data, int len);
 | 
			
		||||
 | 
			
		||||
TNumber getNumberCore(uint8_t *buf, int size, NumberFormat format);
 | 
			
		||||
void setNumberCore(uint8_t *buf, int size, NumberFormat format, TNumber value);
 | 
			
		||||
 | 
			
		||||
TNumber mkNaN();
 | 
			
		||||
 | 
			
		||||
void seedRandom(unsigned seed);
 | 
			
		||||
// max is inclusive
 | 
			
		||||
unsigned getRandom(unsigned max);
 | 
			
		||||
 | 
			
		||||
extern const VTable string_vt;
 | 
			
		||||
extern const VTable image_vt;
 | 
			
		||||
extern const VTable buffer_vt;
 | 
			
		||||
extern const VTable number_vt;
 | 
			
		||||
extern const VTable RefAction_vtable;
 | 
			
		||||
 | 
			
		||||
enum class ValType {
 | 
			
		||||
    Undefined,
 | 
			
		||||
    Boolean,
 | 
			
		||||
    Number,
 | 
			
		||||
    String,
 | 
			
		||||
    Object,
 | 
			
		||||
    Function,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ValType valType(TValue v);
 | 
			
		||||
} // namespace pxt
 | 
			
		||||
 | 
			
		||||
#define PXT_DEF_STRING(name, val)                                                                  \
 | 
			
		||||
    static const char name[] __attribute__((aligned(4))) = "\xff\xff\x01\x00" val;
 | 
			
		||||
 | 
			
		||||
using namespace pxt;
 | 
			
		||||
 | 
			
		||||
namespace pins {
 | 
			
		||||
Buffer createBuffer(int size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace String_ {
 | 
			
		||||
int compare(String s, String that);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
//
 | 
			
		||||
// The vtable pointers are there, so that the ::emptyData for various types
 | 
			
		||||
// can be patched with the right vtable.
 | 
			
		||||
//
 | 
			
		||||
#define PXT_SHIMS_BEGIN                                                                            \
 | 
			
		||||
    namespace pxt {                                                                                \
 | 
			
		||||
    const unsigned functionsAndBytecode[]                                                          \
 | 
			
		||||
        __attribute__((aligned(0x20))) = {0x08010801, 0x42424242, 0x08010801, 0x8de9d83e,
 | 
			
		||||
 | 
			
		||||
#define PXT_SHIMS_END                                                                              \
 | 
			
		||||
    }                                                                                              \
 | 
			
		||||
    ;                                                                                              \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef X86_64
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wpmf-conversions"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_TO_INT(vt) ((uintptr_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,
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_END                                                                             \
 | 
			
		||||
    }                                                                                              \
 | 
			
		||||
    }                                                                                              \
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_INIT(classname) RefObject(PXT_VTABLE_TO_INT(&classname##_vtable))
 | 
			
		||||
 | 
			
		||||
#define PXT_VTABLE_CTOR(classname)                                                                 \
 | 
			
		||||
    PXT_VTABLE_BEGIN(classname, 0, 0)                                                              \
 | 
			
		||||
    PXT_VTABLE_END classname::classname() : PXT_VTABLE_INIT(classname)
 | 
			
		||||
 | 
			
		||||
#define PXT_MAIN                                                                                   \
 | 
			
		||||
    int main() {                                                                                   \
 | 
			
		||||
        pxt::start();                                                                              \
 | 
			
		||||
        return 0;                                                                                  \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define PXT_FNPTR(x) (unsigned)(void *)(x)
 | 
			
		||||
 | 
			
		||||
#define PXT_ABI(...)
 | 
			
		||||
 | 
			
		||||
#define JOIN(a, b) a##b
 | 
			
		||||
/// Defines getClassName() function to fetch the singleton
 | 
			
		||||
#define SINGLETON(ClassName)                                                                       \
 | 
			
		||||
    static ClassName *JOIN(inst, ClassName);                                                       \
 | 
			
		||||
    ClassName *JOIN(get, ClassName)() {                                                            \
 | 
			
		||||
        if (!JOIN(inst, ClassName))                                                                \
 | 
			
		||||
            JOIN(inst, ClassName) = new ClassName();                                               \
 | 
			
		||||
        return JOIN(inst, ClassName);                                                              \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										16
									
								
								libs/core/pxtcore.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								libs/core/pxtcore.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#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 DMESG NOLOG
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -68,8 +68,8 @@ namespace serial {
 | 
			
		||||
    //% 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)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -78,10 +78,10 @@ namespace serial {
 | 
			
		||||
    //% 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));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -90,8 +90,8 @@ namespace serial {
 | 
			
		||||
    */
 | 
			
		||||
    //% 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);
 | 
			
		||||
@@ -103,10 +103,10 @@ namespace serial {
 | 
			
		||||
    //% help=serial/write-string
 | 
			
		||||
    //% weight=87 blockGap=8
 | 
			
		||||
    //% blockId=serial_writestring block="serial|write string %text"
 | 
			
		||||
    void writeString(StringData *text) {
 | 
			
		||||
    void writeString(String text) {
 | 
			
		||||
      if (!text) return;
 | 
			
		||||
 | 
			
		||||
      uBit.serial.send(ManagedString(text));
 | 
			
		||||
      uBit.serial.send(MSTR(text));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -117,8 +117,7 @@ namespace serial {
 | 
			
		||||
    void writeBuffer(Buffer buffer) {
 | 
			
		||||
      if (!buffer) return;
 | 
			
		||||
 | 
			
		||||
      ManagedBuffer buf(buffer);
 | 
			
		||||
      uBit.serial.send(buf.getBytes(), buf.length());
 | 
			
		||||
      uBit.serial.send(buffer->data, buffer->length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -131,12 +130,15 @@ namespace serial {
 | 
			
		||||
      if (length <= 0)
 | 
			
		||||
        length = MICROBIT_SERIAL_READ_BUFFER_LENGTH;
 | 
			
		||||
        
 | 
			
		||||
      ManagedBuffer buf(length);
 | 
			
		||||
      int read = uBit.serial.read(buf.getBytes(), buf.length());
 | 
			
		||||
      if (read != buf.length())
 | 
			
		||||
        buf = buf.slice(read);
 | 
			
		||||
      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.leakData();
 | 
			
		||||
      return buf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -57,8 +57,9 @@ 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
 | 
			
		||||
    //% blockId=device_scroll_image
 | 
			
		||||
    //% block="scroll image %sprite|with offset %frameoffset|and interval (ms) %delay"
 | 
			
		||||
    //% blockGap=8 parts="ledmatrix" shim=ImageMethods::scrollImage
 | 
			
		||||
    scrollImage(frameOffset: int32, interval: int32): void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -852,13 +853,13 @@ declare interface Buffer {
 | 
			
		||||
     * Write a number in specified format in the buffer.
 | 
			
		||||
     */
 | 
			
		||||
    //% shim=BufferMethods::setNumber
 | 
			
		||||
    setNumber(format: NumberFormat, offset: int32, value: int32): 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: int32): int32;
 | 
			
		||||
    getNumber(format: NumberFormat, offset: int32): number;
 | 
			
		||||
 | 
			
		||||
    /** Returns the length of a Buffer object. */
 | 
			
		||||
    //% property shim=BufferMethods::length
 | 
			
		||||
@@ -880,16 +881,24 @@ declare interface 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: int32, start?: int32, length?: int32): void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a buffer to its hexadecimal representation.
 | 
			
		||||
     */
 | 
			
		||||
    //% shim=BufferMethods::toHex
 | 
			
		||||
    toHex(): string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rotate buffer left in place.
 | 
			
		||||
     * @param offset number of bytes to shift; use negative value to shift right
 | 
			
		||||
     * @param start start offset in buffer. Default is 0.
 | 
			
		||||
     * @param length number of elements in buffer. If negative, length is set as the buffer length minus start. eg: -1
 | 
			
		||||
     * @param length number of elements in buffer. If negative, length is set as the buffer length minus
 | 
			
		||||
     * start. eg: -1
 | 
			
		||||
     */
 | 
			
		||||
    //% start.defl=0 length.defl=-1 shim=BufferMethods::rotate
 | 
			
		||||
    rotate(offset: int32, start?: int32, length?: int32): void;
 | 
			
		||||
@@ -900,5 +909,14 @@ declare interface Buffer {
 | 
			
		||||
    //% shim=BufferMethods::write
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Auto-generated. Do not edit. Really.
 | 
			
		||||
 
 | 
			
		||||
@@ -42,8 +42,8 @@ namespace radio {
 | 
			
		||||
    uint32_t time;
 | 
			
		||||
    uint32_t serial;
 | 
			
		||||
    int value;
 | 
			
		||||
    StringData* msg; // may be NULL before first packet
 | 
			
		||||
    BufferData* bufMsg; // may be NULL before first packet
 | 
			
		||||
    String msg; // may be NULL before first packet
 | 
			
		||||
    Buffer bufMsg; // may be NULL before first packet
 | 
			
		||||
 | 
			
		||||
    int radioEnable() {
 | 
			
		||||
        int r = uBit.radio.enable();
 | 
			
		||||
@@ -78,55 +78,43 @@ namespace radio {
 | 
			
		||||
        memcpy(buf + 5, &sn, 4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t copyStringValue(uint8_t* buf, StringData* data, uint8_t maxLength) {
 | 
			
		||||
        ManagedString s(data);
 | 
			
		||||
        uint8_t len = min(maxLength, s.length());
 | 
			
		||||
    uint8_t copyStringValue(uint8_t* buf, String data, uint8_t maxLength) {
 | 
			
		||||
        uint8_t len = min_(maxLength, data->length);
 | 
			
		||||
 | 
			
		||||
        // One byte for length of the string
 | 
			
		||||
        buf[0] = len;
 | 
			
		||||
 | 
			
		||||
        if (len > 0) {
 | 
			
		||||
            memcpy(buf + 1, s.toCharArray(), len);
 | 
			
		||||
            memcpy(buf + 1, data->data, len);
 | 
			
		||||
        }
 | 
			
		||||
        return len + 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    StringData* getStringValue(uint8_t* buf, uint8_t maxLength) {
 | 
			
		||||
    String getStringValue(uint8_t* buf, uint8_t maxLength) {
 | 
			
		||||
        // First byte is the string length
 | 
			
		||||
        uint8_t len = min(maxLength, buf[0]);
 | 
			
		||||
 | 
			
		||||
        if (len) {
 | 
			
		||||
            char name[len + 1];
 | 
			
		||||
            memcpy(name, buf + 1, len);
 | 
			
		||||
            name[len] = 0;
 | 
			
		||||
            return ManagedString(name).leakData();
 | 
			
		||||
        }
 | 
			
		||||
        return ManagedString().leakData();
 | 
			
		||||
        uint8_t len = min_(maxLength, buf[0]);
 | 
			
		||||
        return mkString((char*)buf + 1, len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t copyBufferValue(uint8_t* buf, BufferData* data, uint8_t maxLength) {
 | 
			
		||||
        ManagedBuffer s(data);
 | 
			
		||||
        uint8_t len = min(maxLength, s.length());
 | 
			
		||||
    uint8_t copyBufferValue(uint8_t* buf, Buffer data, uint8_t maxLength) {
 | 
			
		||||
        uint8_t len = min_(maxLength, data->length);
 | 
			
		||||
 | 
			
		||||
        // One byte for length of the buffer
 | 
			
		||||
        buf[0] = len;
 | 
			
		||||
        if (len > 0) {
 | 
			
		||||
            memcpy(buf + 1, s.getBytes(), len);
 | 
			
		||||
            memcpy(buf + 1, data->data, len);
 | 
			
		||||
        }
 | 
			
		||||
        return len + 1;
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    BufferData* getBufferValue(uint8_t* buf, uint8_t maxLength) {
 | 
			
		||||
    Buffer getBufferValue(uint8_t* buf, uint8_t maxLength) {
 | 
			
		||||
        // First byte is the buffer length
 | 
			
		||||
        uint8_t len = min(maxLength, buf[0]);
 | 
			
		||||
        if (len) {
 | 
			
		||||
            // skip first byte
 | 
			
		||||
            return ManagedBuffer(buf + 1, len).leakData();
 | 
			
		||||
        }
 | 
			
		||||
        return ManagedBuffer().leakData();
 | 
			
		||||
        uint8_t len = min_(maxLength, buf[0]);
 | 
			
		||||
        // skip first byte
 | 
			
		||||
        return mkBuffer(buf + 1, len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void writePacketAsJSON(uint8_t tp, int v, int s, int t, StringData* m, BufferData* b) {
 | 
			
		||||
    void writePacketAsJSON(uint8_t tp, int v, int s, int t, String m, Buffer b) {
 | 
			
		||||
        // Convert the packet to JSON and send over serial
 | 
			
		||||
        uBit.serial.send("{");
 | 
			
		||||
        uBit.serial.send("\"t\":");
 | 
			
		||||
@@ -135,14 +123,13 @@ namespace radio {
 | 
			
		||||
        uBit.serial.send(s);
 | 
			
		||||
        if ((tp == PACKET_TYPE_STRING || tp == PACKET_TYPE_VALUE) && NULL != m) {
 | 
			
		||||
            uBit.serial.send(",\"n\":\"");
 | 
			
		||||
            uBit.serial.send(ManagedString(m));
 | 
			
		||||
            uBit.serial.send((uint8_t*)m->data, m->length);
 | 
			
		||||
            uBit.serial.send("\"");
 | 
			
		||||
        }
 | 
			
		||||
        if (tp == PACKET_TYPE_BUFFER && NULL != b) {
 | 
			
		||||
            ManagedBuffer mb(b);
 | 
			
		||||
            uBit.serial.send(",\"b\":\"");
 | 
			
		||||
            // TODO: proper base64 encoding
 | 
			
		||||
            uBit.serial.send(mb.getBytes(), mb.length());
 | 
			
		||||
            uBit.serial.send(b->data, b->length);
 | 
			
		||||
            uBit.serial.send("\"");
 | 
			
		||||
        }
 | 
			
		||||
        if (tp == PACKET_TYPE_NUMBER || tp == PACKET_TYPE_VALUE) {
 | 
			
		||||
@@ -165,8 +152,8 @@ namespace radio {
 | 
			
		||||
        int t;
 | 
			
		||||
        int s;
 | 
			
		||||
        int v = 0;
 | 
			
		||||
        StringData* m = NULL;
 | 
			
		||||
        BufferData* b = NULL;
 | 
			
		||||
        String m = NULL;
 | 
			
		||||
        Buffer b = NULL;
 | 
			
		||||
 | 
			
		||||
        memcpy(&tp, buf, 1);
 | 
			
		||||
        memcpy(&t, buf + 1, 4);
 | 
			
		||||
@@ -186,9 +173,9 @@ namespace radio {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (NULL == m)
 | 
			
		||||
            m = ManagedString().leakData();
 | 
			
		||||
            m = mkString("", 0);
 | 
			
		||||
        if (NULL == b)
 | 
			
		||||
            b = ManagedBuffer().leakData();
 | 
			
		||||
            b = mkBuffer(NULL, 0);
 | 
			
		||||
 | 
			
		||||
        if (!writeToSerial) {
 | 
			
		||||
            // Refresh global packet
 | 
			
		||||
@@ -197,11 +184,15 @@ namespace radio {
 | 
			
		||||
            time = t;
 | 
			
		||||
            serial = s;
 | 
			
		||||
            value = v;
 | 
			
		||||
            decrRC(msg);
 | 
			
		||||
            decrRC(bufMsg);
 | 
			
		||||
            msg = m;
 | 
			
		||||
            bufMsg = b;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            writePacketAsJSON(tp, v, s, t, m, b);
 | 
			
		||||
            decrRC(m);
 | 
			
		||||
            decrRC(b);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -232,10 +223,9 @@ namespace radio {
 | 
			
		||||
    //% help=radio/send-value
 | 
			
		||||
    //% weight=59
 | 
			
		||||
    //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8
 | 
			
		||||
    void sendValue(StringData* name, int value) {
 | 
			
		||||
    void sendValue(String name, int value) {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
			
		||||
 | 
			
		||||
        ManagedString n(name);
 | 
			
		||||
        uint8_t buf[32];
 | 
			
		||||
        memset(buf, 0, 32);
 | 
			
		||||
 | 
			
		||||
@@ -254,7 +244,7 @@ namespace radio {
 | 
			
		||||
    //% help=radio/send-string
 | 
			
		||||
    //% weight=58
 | 
			
		||||
    //% blockId=radio_datagram_send_string block="radio send string %msg"
 | 
			
		||||
    void sendString(StringData* msg) {
 | 
			
		||||
    void sendString(String msg) {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return;
 | 
			
		||||
 | 
			
		||||
        uint8_t buf[32];
 | 
			
		||||
@@ -350,8 +340,8 @@ namespace radio {
 | 
			
		||||
    //% weight=44
 | 
			
		||||
    //% help=radio/receive-string
 | 
			
		||||
    //% deprecated=true
 | 
			
		||||
    StringData* receiveString() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK) return ManagedString().leakData();
 | 
			
		||||
    String receiveString() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK) return mkString("", 0);
 | 
			
		||||
        receivePacket(false);
 | 
			
		||||
        return msg;
 | 
			
		||||
    }
 | 
			
		||||
@@ -438,8 +428,9 @@ namespace radio {
 | 
			
		||||
     * packet did not contain a string.
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/received-string
 | 
			
		||||
    StringData* receivedString() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return ManagedString().leakData();
 | 
			
		||||
    String receivedString() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return mkString("", 0);
 | 
			
		||||
        incrRC(msg);
 | 
			
		||||
        return msg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -450,7 +441,8 @@ namespace radio {
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/received-buffer
 | 
			
		||||
    Buffer receivedBuffer() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == bufMsg) return ManagedBuffer().leakData();
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == bufMsg) return mkBuffer(NULL, 0);
 | 
			
		||||
        incrRC(bufMsg);
 | 
			
		||||
        return bufMsg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user