From 63e24ce90a166b5bc675d76eb688928e43638f3f Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 29 Nov 2016 08:59:54 -0800 Subject: [PATCH 1/6] support for setting music pin using analogSetPitchPin --- docs/reference/music/play-tone.md | 9 ++++++++ docs/reference/music/ring-tone.md | 8 +++++++ docs/reference/pins/analog-pitch.md | 4 +++- libs/core/_locales/core-jsdoc-strings.json | 8 +++---- libs/core/_locales/core-strings.json | 2 ++ libs/core/music.ts | 2 -- libs/core/pins.cpp | 27 ++++++++++++---------- libs/core/pins.ts | 4 ++-- libs/core/shims.d.ts | 24 ++++++++++--------- 9 files changed, 56 insertions(+), 32 deletions(-) diff --git a/docs/reference/music/play-tone.md b/docs/reference/music/play-tone.md index 39276e0b..d10019b0 100644 --- a/docs/reference/music/play-tone.md +++ b/docs/reference/music/play-tone.md @@ -25,6 +25,15 @@ let freq = music.noteFrequency(Note.C) music.playTone(freq, 1000) ``` + +### Using other pins + +Use [analogSetPitchPin](/pins/analog-set-pitch-pin) to change that pin used to generate music. + +```blocks +pins.analogSetPitchPin(AnalogPin.P1); +``` + ### See also [rest](/reference/music/rest), [ring tone](/reference/music/ring-tone) , [tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo), diff --git a/docs/reference/music/ring-tone.md b/docs/reference/music/ring-tone.md index 2da40aeb..33ffff1d 100644 --- a/docs/reference/music/ring-tone.md +++ b/docs/reference/music/ring-tone.md @@ -32,6 +32,14 @@ basic.forever(() => { }) ``` +### Using other pins + +Use [analogSetPitchPin](/pins/analog-set-pitch-pin) to change that pin used to generate music. + +```blocks +pins.analogSetPitchPin(AnalogPin.P1); +``` + ### See also [rest](/reference/music/rest), [play tone](/reference/music/play-tone), diff --git a/docs/reference/pins/analog-pitch.md b/docs/reference/pins/analog-pitch.md index 603d5c29..193bc0a0 100644 --- a/docs/reference/pins/analog-pitch.md +++ b/docs/reference/pins/analog-pitch.md @@ -1,6 +1,7 @@ # Analog Pitch -Emits a Pulse With Modulation (PWM) signal to the current pitch [pin](/device/pins). Use [analog set pitch pin](/reference/pins/analog-set-pitch-pin) to set the current pitch pin. +Emits a Pulse With Modulation (PWM) signal to the pin ``P0``. +Use [analog set pitch pin](/reference/pins/analog-set-pitch-pin) to set the current pitch pin. ```sig pins.analogPitch(440, 300) @@ -17,6 +18,7 @@ pins.analogPitch(440, 300) pins.analogSetPitchPin("P0") let frequency1 = 440 let duration = 1000 +pins.analogSetPitchPin(AnalogPin.P1); pins.analogPitch(frequency1, duration) ``` diff --git a/libs/core/_locales/core-jsdoc-strings.json b/libs/core/_locales/core-jsdoc-strings.json index ceb0891a..7b23ac25 100644 --- a/libs/core/_locales/core-jsdoc-strings.json +++ b/libs/core/_locales/core-jsdoc-strings.json @@ -179,15 +179,15 @@ "music.tempo": "Returns the tempo in beats per minute. Tempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play.", "pins": "Control currents in Pins for analog/digital signals, servos, i2c, ...", "pins.analogPitch": "Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin.", - "pins.analogPitch|param|frequency": "TODO", - "pins.analogPitch|param|ms": "TODO", + "pins.analogPitch|param|frequency": "frequency to modulate in Hz.", + "pins.analogPitch|param|ms": "duration of the pitch in milli seconds.", "pins.analogReadPin": "Read the connector value as analog, that is, as a value comprised between 0 and 1023.", "pins.analogReadPin|param|name": "pin to write to", "pins.analogSetPeriod": "Configures the Pulse-width modulation (PWM) of the analog output to the given value in **microseconds** or `1/1000` milliseconds.\nIf this pin is not configured as an analog output (using `analog write pin`), the operation has no effect.", "pins.analogSetPeriod|param|micros": "period in micro seconds. eg:20000", "pins.analogSetPeriod|param|name": "analog pin to set period to", - "pins.analogSetPitchPin": "Sets the pin used when using `pins->analog pitch`.", - "pins.analogSetPitchPin|param|name": "TODO", + "pins.analogSetPitchPin": "Sets the pin used when using `analog pitch` or music.", + "pins.analogSetPitchPin|param|name": "pin to modulate pitch from", "pins.analogWritePin": "Set the connector value as analog. Value must be comprised between 0 and 1023.", "pins.analogWritePin|param|name": "pin name to write to", "pins.analogWritePin|param|value": "value to write to the pin between ``0`` and ``1023``. eg:1023,0", diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index 6031242d..392312bd 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -146,8 +146,10 @@ "music.setTempo|block": "set tempo to (bpm)|%value", "music.tempo|block": "tempo (bpm)", "music|block": "music", + "pins.analogPitch|block": "analog pitch %frequency|for (ms) %ms", "pins.analogReadPin|block": "analog read|pin %name", "pins.analogSetPeriod|block": "analog set period|pin %pin|to (µs)%micros", + "pins.analogSetPitchPin|block": "analog set pitch pin %name", "pins.analogWritePin|block": "analog write|pin %name|to %value", "pins.digitalReadPin|block": "digital read|pin %name", "pins.digitalWritePin|block": "digital write|pin %name|to %value", diff --git a/libs/core/music.ts b/libs/core/music.ts index 9c3e43fb..86267c8c 100644 --- a/libs/core/music.ts +++ b/libs/core/music.ts @@ -138,7 +138,6 @@ namespace music { //% blockId=device_play_note block="play|tone %note=device_note|for %duration=device_beat" icon="\uf025" blockGap=8 //% parts="headphone" export function playTone(frequency: number, ms: number): void { - pins.analogSetPitchPin(AnalogPin.P0); pins.analogPitch(frequency, ms); } @@ -150,7 +149,6 @@ namespace music { //% blockId=device_ring block="ring tone (Hz)|%note=device_note" icon="\uf025" blockGap=8 //% parts="headphone" export function ringTone(frequency: number): void { - pins.analogSetPitchPin(AnalogPin.P0); pins.analogPitch(frequency, 0); } diff --git a/libs/core/pins.cpp b/libs/core/pins.cpp index 0d5a46cf..bdc7a9e1 100644 --- a/libs/core/pins.cpp +++ b/libs/core/pins.cpp @@ -147,7 +147,7 @@ namespace pins { /** * Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``. */ - //% help=pins/on-pulsed weight=22 blockGap=8 + //% help=pins/on-pulsed weight=22 blockGap=8 advanced=true //% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse" void onPulsed(DigitalPin name, PulseValue pulse, Action body) { MicroBitPin* pin = getPin((int)name); @@ -160,7 +160,7 @@ namespace pins { /** * Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler. */ - //% help=pins/pulse-duration + //% help=pins/pulse-duration advanced=true //% blockId=pins_pulse_duration block="pulse duration (µs)" //% weight=21 blockGap=8 int pulseDuration() { @@ -174,7 +174,7 @@ namespace pins { * @param maximum duration in micro-seconds */ //% blockId="pins_pulse_in" block="pulse in (µs)|pin %name|pulsed %value" - //% weight=20 + //% weight=20 advanced=true int pulseIn(DigitalPin name, PulseValue value, int maxDuration = 2000000) { MicroBitPin* pin = getPin((int)name); if (!pin) return 0; @@ -223,22 +223,25 @@ namespace pins { MicroBitPin* pitchPin = NULL; /** - * Sets the pin used when using `pins->analog pitch`. - * @param name TODO + * Sets the pin used when using `analog pitch` or music. + * @param name pin to modulate pitch from */ - //% help=pins/analog-set-pitch weight=12 + //% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name" + //% help=pins/analog-set-pitch weight=3 advanced=true void analogSetPitchPin(AnalogPin name) { pitchPin = getPin((int)name); } /** * Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. - * @param frequency TODO - * @param ms TODO + * @param frequency frequency to modulate in Hz. + * @param ms duration of the pitch in milli seconds. */ - //% help=pins/analog-pitch weight=14 async + //% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms" + //% help=pins/analog-pitch weight=4 async advanced=true blockGap=8 void analogPitch(int frequency, int ms) { - if (pitchPin == NULL) return; + if (pitchPin == NULL) + analogSetPitchPin(AnalogPin::P0); if (frequency <= 0) { pitchPin->setAnalogValue(0); } else { @@ -260,7 +263,7 @@ namespace pins { * @param name pin to set the pull mode on * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone */ - //% help=pins/set-pull weight=3 + //% help=pins/set-pull weight=3 advanced=true //% blockId=device_set_pull block="set pull|pin %pin|to %pull" void setPull(DigitalPin name, PinPullMode pull) { PinMode m = pull == PinPullMode::PullDown @@ -311,7 +314,7 @@ namespace pins { * Write to the SPI slave and return the response * @param value Data to be sent to the SPI slave */ - //% help=pins/spi-write weight=5 + //% help=pins/spi-write weight=5 advanced=true //% blockId=spi_write block="spi write %value" int spiWrite(int value) { auto p = allocSPI(); diff --git a/libs/core/pins.ts b/libs/core/pins.ts index 2b9bc3c1..a2152e0a 100644 --- a/libs/core/pins.ts +++ b/libs/core/pins.ts @@ -21,7 +21,7 @@ namespace pins { /** * Read one number from 7-bit I2C address. */ - //% help=pins/i2c-read-number blockGap=8 + //% help=pins/i2c-read-number blockGap=8 advanced=true //% blockId=pins_i2c_readnumber block="i2c read number|at address %address|of format %format=i2c_sizeof" weight=7 export function i2cReadNumber(address: number, format: NumberFormat): number { let buf = pins.i2cReadBuffer(address, pins.sizeOf(format)) @@ -31,7 +31,7 @@ namespace pins { /** * Write one number to a 7-bit I2C address. */ - //% help=pins/i2c-write-number blockGap=8 + //% help=pins/i2c-write-number blockGap=8 advanced=true //% blockId=i2c_writenumber block="i2c write number|at address %address|with value %value|of format %format=i2c_sizeof" weight=6 export function i2cWriteNumber(address: number, value: number, format: NumberFormat): void { let buf = createBuffer(pins.sizeOf(format)) diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index 8ef6489b..5eca9bc8 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -557,14 +557,14 @@ declare namespace pins { /** * Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either ``high`` or ``low``. */ - //% help=pins/on-pulsed weight=22 blockGap=8 + //% help=pins/on-pulsed weight=22 blockGap=8 advanced=true //% blockId=pins_on_pulsed block="on|pin %pin|pulsed %pulse" shim=pins::onPulsed function onPulsed(name: DigitalPin, pulse: PulseValue, body: () => void): void; /** * Gets the duration of the last pulse in micro-seconds. This function should be called from a ``onPulsed`` handler. */ - //% help=pins/pulse-duration + //% help=pins/pulse-duration advanced=true //% blockId=pins_pulse_duration block="pulse duration (µs)" //% weight=21 blockGap=8 shim=pins::pulseDuration function pulseDuration(): number; @@ -576,7 +576,7 @@ declare namespace pins { * @param maximum duration in micro-seconds */ //% blockId="pins_pulse_in" block="pulse in (µs)|pin %name|pulsed %value" - //% weight=20 maxDuration.defl=2000000 shim=pins::pulseIn + //% weight=20 advanced=true maxDuration.defl=2000000 shim=pins::pulseIn function pulseIn(name: DigitalPin, value: PulseValue, maxDuration?: number): number; /** @@ -599,18 +599,20 @@ declare namespace pins { function servoSetPulse(name: AnalogPin, micros: number): void; /** - * Sets the pin used when using `pins->analog pitch`. - * @param name TODO + * Sets the pin used when using `analog pitch` or music. + * @param name pin to modulate pitch from */ - //% help=pins/analog-set-pitch weight=12 shim=pins::analogSetPitchPin + //% blockId=device_analog_set_pitch_pin block="analog set pitch pin %name" + //% help=pins/analog-set-pitch weight=3 advanced=true shim=pins::analogSetPitchPin function analogSetPitchPin(name: AnalogPin): void; /** * Emits a Pulse-width modulation (PWM) signal to the current pitch pin. Use `analog set pitch pin` to define the pitch pin. - * @param frequency TODO - * @param ms TODO + * @param frequency frequency to modulate in Hz. + * @param ms duration of the pitch in milli seconds. */ - //% help=pins/analog-pitch weight=14 async shim=pins::analogPitch + //% blockId=device_analog_pitch block="analog pitch %frequency|for (ms) %ms" + //% help=pins/analog-pitch weight=4 async advanced=true blockGap=8 shim=pins::analogPitch function analogPitch(frequency: number, ms: number): void; /** @@ -618,7 +620,7 @@ declare namespace pins { * @param name pin to set the pull mode on * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone */ - //% help=pins/set-pull weight=3 + //% help=pins/set-pull weight=3 advanced=true //% blockId=device_set_pull block="set pull|pin %pin|to %pull" shim=pins::setPull function setPull(name: DigitalPin, pull: PinPullMode): void; @@ -645,7 +647,7 @@ declare namespace pins { * Write to the SPI slave and return the response * @param value Data to be sent to the SPI slave */ - //% help=pins/spi-write weight=5 + //% help=pins/spi-write weight=5 advanced=true //% blockId=spi_write block="spi write %value" shim=pins::spiWrite function spiWrite(value: number): number; } From 98e4f80399541085c80a3704972becf7ff41b876 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 29 Nov 2016 13:12:32 -0800 Subject: [PATCH 2/6] updated crowdin info --- pxtarget.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pxtarget.json b/pxtarget.json index 54a0ed36..249c1491 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -188,6 +188,7 @@ "termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977", "githubUrl": "https://github.com/Microsoft/pxt-microbit", "projectGallery": "projects", + "crowdinProject": "kindscript", "boardName": "micro:bit", "sideDoc": "getting-started", "browserSupport": [ From 90f48ac77ae3f247d37d91f5a889748a34c8654b Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Tue, 29 Nov 2016 14:53:26 -0800 Subject: [PATCH 3/6] Enable reference help switch in javascript editor. --- pxtarget.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pxtarget.json b/pxtarget.json index 249c1491..a4576f14 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -248,6 +248,7 @@ "path": "/device" } ], + "hasReferenceDocs": true, "usbDocs": "/device/usb", "usbHelp": [ { From f046f0e50ca1fcf7ca50e9259605db918c927c6f Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 29 Nov 2016 15:06:34 -0800 Subject: [PATCH 4/6] merging pxt-microbit-core into the target --- libs/core/ManagedBuffer.cpp | 373 ++++++++++++++++++++++++++++ libs/core/ManagedBuffer.h | 257 ++++++++++++++++++++ libs/core/dal.d.ts | 116 ++++----- libs/core/pxt.cpp | 472 ++++++++++++++++++++++++++++++++++++ libs/core/pxt.h | 333 +++++++++++++++++++++++++ libs/core/pxt.json | 4 + pxtarget.json | 8 +- 7 files changed, 1502 insertions(+), 61 deletions(-) create mode 100644 libs/core/ManagedBuffer.cpp create mode 100644 libs/core/ManagedBuffer.h create mode 100644 libs/core/pxt.cpp create mode 100644 libs/core/pxt.h diff --git a/libs/core/ManagedBuffer.cpp b/libs/core/ManagedBuffer.cpp new file mode 100644 index 00000000..25b9cb26 --- /dev/null +++ b/libs/core/ManagedBuffer.cpp @@ -0,0 +1,373 @@ +#include "MicroBit.h" +#include "ManagedBuffer.h" +#include + +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; +} diff --git a/libs/core/ManagedBuffer.h b/libs/core/ManagedBuffer.h new file mode 100644 index 00000000..991dd8d7 --- /dev/null +++ b/libs/core/ManagedBuffer.h @@ -0,0 +1,257 @@ +#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 + diff --git a/libs/core/dal.d.ts b/libs/core/dal.d.ts index df1bbfc1..7e7f4134 100644 --- a/libs/core/dal.d.ts +++ b/libs/core/dal.d.ts @@ -1,11 +1,11 @@ // Auto-generated. Do not edit. declare const enum DAL { - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\ExternalEvents.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/ExternalEvents.h MICROBIT_ID_BLE = 1000, MICROBIT_ID_BLE_UART = 1200, MICROBIT_BLE_EVT_CONNECTED = 1, MICROBIT_BLE_EVT_DISCONNECTED = 2, - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MESEvents.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MESEvents.h MES_REMOTE_CONTROL_ID = 1001, MES_REMOTE_CONTROL_EVT_PLAY = 1, MES_REMOTE_CONTROL_EVT_PAUSE = 2, @@ -70,8 +70,8 @@ declare const enum DAL { MES_DPAD_BUTTON_4_DOWN = 15, MES_DPAD_BUTTON_4_UP = 16, MES_BROADCAST_GENERAL_ID = 2000, - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitAccelerometerService.h - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitBLEManager.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitAccelerometerService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitBLEManager.h MICROBIT_BLE_PAIR_REQUEST = 0x01, MICROBIT_BLE_PAIR_COMPLETE = 0x02, MICROBIT_BLE_PAIR_PASSCODE = 0x04, @@ -79,27 +79,29 @@ declare const enum DAL { MICROBIT_BLE_PAIRING_TIMEOUT = 90, MICROBIT_BLE_POWER_LEVELS = 8, MICROBIT_BLE_MAXIMUM_BONDS = 4, - MICROBIT_BLE_EDDYSTONE_URL_ADV_INTERVAL = 400, - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitButtonService.h - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitDFUService.h + MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL = 400, + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitButtonService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitDFUService.h MICROBIT_DFU_OPCODE_START_DFU = 1, MICROBIT_DFU_HISTOGRAM_WIDTH = 5, MICROBIT_DFU_HISTOGRAM_HEIGHT = 5, - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitEventService.h - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitIOPinService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitEddystone.h + MICROBIT_BLE_EDDYSTONE_URL_ADV_INTERVAL = 400, + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitEventService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitIOPinService.h MICROBIT_IO_PIN_SERVICE_PINCOUNT = 19, MICROBIT_IO_PIN_SERVICE_DATA_SIZE = 10, MICROBIT_PWM_PIN_SERVICE_DATA_SIZE = 2, - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitLEDService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitLEDService.h MICROBIT_BLE_MAXIMUM_SCROLLTEXT = 20, - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitMagnetometerService.h - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitTemperatureService.h - // built\yt\yotta_modules\microbit-dal\inc\bluetooth\MicroBitUARTService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitMagnetometerService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitTemperatureService.h + // built/yt/yotta_modules/microbit-dal/inc/bluetooth/MicroBitUARTService.h MICROBIT_UART_S_DEFAULT_BUF_SIZE = 20, MICROBIT_UART_S_EVT_DELIM_MATCH = 1, MICROBIT_UART_S_EVT_HEAD_MATCH = 2, MICROBIT_UART_S_EVT_RX_FULL = 3, - // built\yt\yotta_modules\microbit-dal\inc\core\ErrorNo.h + // built/yt/yotta_modules/microbit-dal/inc/core/ErrorNo.h MICROBIT_OK = 0, MICROBIT_INVALID_PARAMETER = -1001, MICROBIT_NOT_SUPPORTED = -1002, @@ -114,10 +116,10 @@ declare const enum DAL { MICROBIT_OOM = 20, MICROBIT_HEAP_ERROR = 30, MICROBIT_NULL_DEREFERENCE = 40, - // built\yt\yotta_modules\microbit-dal\inc\core\EventModel.h - // built\yt\yotta_modules\microbit-dal\inc\core\MemberFunctionCallback.h - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitCompat.h - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitComponent.h + // built/yt/yotta_modules/microbit-dal/inc/core/EventModel.h + // built/yt/yotta_modules/microbit-dal/inc/core/MemberFunctionCallback.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitCompat.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitComponent.h MICROBIT_ID_BUTTON_A = 1, MICROBIT_ID_BUTTON_B = 2, MICROBIT_ID_BUTTON_RESET = 3, @@ -155,25 +157,25 @@ declare const enum DAL { MICROBIT_ID_NOTIFY_ONE = 1022, MICROBIT_ID_NOTIFY = 1023, MICROBIT_COMPONENT_RUNNING = 0x01, - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitDevice.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitDevice.h MICROBIT_NAME_LENGTH = 5, MICROBIT_NAME_CODE_LETTERS = 5, MICROBIT_PANIC_ERROR_CHARS = 4, - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitFiber.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitFiber.h MICROBIT_SCHEDULER_RUNNING = 0x01, MICROBIT_FIBER_FLAG_FOB = 0x01, MICROBIT_FIBER_FLAG_PARENT = 0x02, MICROBIT_FIBER_FLAG_CHILD = 0x04, MICROBIT_FIBER_FLAG_DO_NOT_PAGE = 0x08, - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitFont.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitFont.h MICROBIT_FONT_WIDTH = 5, MICROBIT_FONT_HEIGHT = 5, MICROBIT_FONT_ASCII_START = 32, MICROBIT_FONT_ASCII_END = 126, - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitHeapAllocator.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitHeapAllocator.h MICROBIT_MAXIMUM_HEAPS = 2, MICROBIT_HEAP_BLOCK_FREE = 0x80000000, - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitListener.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitListener.h MESSAGE_BUS_LISTENER_PARAMETERISED = 0x0001, MESSAGE_BUS_LISTENER_METHOD = 0x0002, MESSAGE_BUS_LISTENER_BUSY = 0x0004, @@ -183,17 +185,17 @@ declare const enum DAL { MESSAGE_BUS_LISTENER_NONBLOCKING = 0x0040, MESSAGE_BUS_LISTENER_URGENT = 0x0080, MESSAGE_BUS_LISTENER_DELETING = 0x8000, - // built\yt\yotta_modules\microbit-dal\inc\core\MicroBitSystemTimer.h - // built\yt\yotta_modules\microbit-dal\inc\core\NotifyEvents.h + // built/yt/yotta_modules/microbit-dal/inc/core/MicroBitSystemTimer.h + // built/yt/yotta_modules/microbit-dal/inc/core/NotifyEvents.h MICROBIT_DISPLAY_EVT_FREE = 1, MICROBIT_SERIAL_EVT_TX_EMPTY = 2, MICROBIT_UART_S_EVT_TX_EMPTY = 3, - // built\yt\yotta_modules\microbit-dal\inc\drivers\DynamicPwm.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/DynamicPwm.h NO_PWMS = 3, MICROBIT_DEFAULT_PWM_PERIOD = 20000, PWM_PERSISTENCE_TRANSIENT = 1, PWM_PERSISTENCE_PERSISTENT = 2, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitAccelerometer.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitAccelerometer.h MICROBIT_ACCEL_PITCH_ROLL_VALID = 0x02, MICROBIT_ACCEL_ADDED_TO_IDLE = 0x04, MMA8653_DEFAULT_ADDR = 0x3A, @@ -233,7 +235,7 @@ declare const enum DAL { MICROBIT_ACCELEROMETER_SHAKE_DAMPING = 10, MICROBIT_ACCELEROMETER_SHAKE_RTX = 30, MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD = 4, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitButton.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitButton.h MICROBIT_BUTTON_EVT_DOWN = 1, MICROBIT_BUTTON_EVT_UP = 2, MICROBIT_BUTTON_EVT_CLICK = 3, @@ -253,7 +255,7 @@ declare const enum DAL { MICROBIT_BUTTON_DOUBLE_CLICK_THRESH = 50, MICROBIT_BUTTON_SIMPLE_EVENTS = 0, MICROBIT_BUTTON_ALL_EVENTS = 1, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitCompass.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitCompass.h MAG3110_DEFAULT_ADDR = 0x1D, MAG_DR_STATUS = 0x00, MAG_OUT_X_MSB = 0x01, @@ -284,8 +286,8 @@ declare const enum DAL { MICROBIT_COMPASS_STATUS_CALIBRATING = 4, MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE = 8, MAG3110_WHOAMI_VAL = 0xC4, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitCompassCalibrator.h - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitDisplay.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitCompassCalibrator.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitDisplay.h MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE = 1, MICROBIT_DISPLAY_EVT_LIGHT_SENSE = 2, MICROBIT_DISPLAY_DEFAULT_AUTOCLEAR = 1, @@ -307,8 +309,8 @@ declare const enum DAL { MICROBIT_DISPLAY_ROTATION_90 = 1, MICROBIT_DISPLAY_ROTATION_180 = 2, MICROBIT_DISPLAY_ROTATION_270 = 3, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitFile.h - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitFileSystem.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitFile.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitFileSystem.h MBFS_FILENAME_LENGTH = 16, MB_READ = 0x01, MB_WRITE = 0x02, @@ -329,23 +331,23 @@ declare const enum DAL { MBFS_BLOCK_TYPE_FILE = 1, MBFS_BLOCK_TYPE_DIRECTORY = 2, MBFS_BLOCK_TYPE_FILETABLE = 3, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitFlash.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitFlash.h PAGE_SIZE = 1024, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitI2C.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitI2C.h MICROBIT_I2C_MAX_RETRIES = 9, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitIO.h - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitLightSensor.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitIO.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitLightSensor.h MICROBIT_LIGHT_SENSOR_CHAN_NUM = 3, MICROBIT_LIGHT_SENSOR_AN_SET_TIME = 4000, MICROBIT_LIGHT_SENSOR_TICK_PERIOD = 5, MICROBIT_LIGHT_SENSOR_MAX_VALUE = 338, MICROBIT_LIGHT_SENSOR_MIN_VALUE = 75, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitMatrixMaps.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitMatrixMaps.h NO_CONN = 0, MICROBIT_DISPLAY_WIDTH = 5, MICROBIT_DISPLAY_HEIGHT = 5, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitMessageBus.h - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitMultiButton.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitMessageBus.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitMultiButton.h MICROBIT_MULTI_BUTTON_STATE_1 = 0x01, MICROBIT_MULTI_BUTTON_STATE_2 = 0x02, MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1 = 0x04, @@ -353,7 +355,7 @@ declare const enum DAL { MICROBIT_MULTI_BUTTON_SUPRESSED_1 = 0X10, MICROBIT_MULTI_BUTTON_SUPRESSED_2 = 0x20, MICROBIT_MULTI_BUTTON_ATTACHED = 0x40, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitPin.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitPin.h IO_STATUS_DIGITAL_IN = 0x01, IO_STATUS_DIGITAL_OUT = 0x02, IO_STATUS_ANALOG_IN = 0x04, @@ -375,7 +377,7 @@ declare const enum DAL { MICROBIT_PIN_EVT_PULSE_LO = 5, PIN_CAPABILITY_DIGITAL = 0x01, PIN_CAPABILITY_ANALOG = 0x02, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitRadio.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitRadio.h MICROBIT_RADIO_STATUS_INITIALISED = 0x0001, MICROBIT_RADIO_BASE_ADDRESS = 0x75626974, MICROBIT_RADIO_DEFAULT_GROUP = 0, @@ -387,9 +389,9 @@ declare const enum DAL { MICROBIT_RADIO_PROTOCOL_DATAGRAM = 1, MICROBIT_RADIO_PROTOCOL_EVENTBUS = 2, MICROBIT_RADIO_EVT_DATAGRAM = 1, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitRadioDatagram.h - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitRadioEvent.h - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitSerial.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitRadioDatagram.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitRadioEvent.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitSerial.h MICROBIT_SERIAL_DEFAULT_BAUD_RATE = 115200, MICROBIT_SERIAL_DEFAULT_BUFFER_SIZE = 20, MICROBIT_SERIAL_EVT_DELIM_MATCH = 1, @@ -402,31 +404,31 @@ declare const enum DAL { ASYNC = 0, SYNC_SPINWAIT = 1, SYNC_SLEEP = 2, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitStorage.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitStorage.h MICROBIT_STORAGE_MAGIC = 0xCAFE, MICROBIT_STORAGE_BLOCK_SIZE = 48, MICROBIT_STORAGE_KEY_SIZE = 16, MICROBIT_STORAGE_STORE_PAGE_OFFSET = 17, MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET = 19, - // built\yt\yotta_modules\microbit-dal\inc\drivers\MicroBitThermometer.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/MicroBitThermometer.h MICROBIT_THERMOMETER_PERIOD = 1000, MICROBIT_THERMOMETER_EVT_UPDATE = 1, MICROBIT_THERMOMETER_ADDED_TO_IDLE = 2, - // built\yt\yotta_modules\microbit-dal\inc\drivers\TimedInterruptIn.h - // built\yt\yotta_modules\microbit-dal\inc\platform\yotta_cfg_mappings.h - // built\yt\yotta_modules\microbit-dal\inc\types\ManagedString.h - // built\yt\yotta_modules\microbit-dal\inc\types\ManagedType.h - // built\yt\yotta_modules\microbit-dal\inc\types\Matrix4.h - // built\yt\yotta_modules\microbit-dal\inc\types\MicroBitCoordinateSystem.h + // built/yt/yotta_modules/microbit-dal/inc/drivers/TimedInterruptIn.h + // built/yt/yotta_modules/microbit-dal/inc/platform/yotta_cfg_mappings.h + // built/yt/yotta_modules/microbit-dal/inc/types/ManagedString.h + // built/yt/yotta_modules/microbit-dal/inc/types/ManagedType.h + // built/yt/yotta_modules/microbit-dal/inc/types/Matrix4.h + // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitCoordinateSystem.h RAW = 0, SIMPLE_CARTESIAN = 1, NORTH_EAST_DOWN = 2, - // built\yt\yotta_modules\microbit-dal\inc\types\MicroBitEvent.h + // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitEvent.h MICROBIT_ID_ANY = 0, MICROBIT_EVT_ANY = 0, CREATE_ONLY = 0, CREATE_AND_FIRE = 1, - // built\yt\yotta_modules\microbit-dal\inc\types\MicroBitImage.h - // built\yt\yotta_modules\microbit-dal\inc\types\PacketBuffer.h - // built\yt\yotta_modules\microbit-dal\inc\types\RefCounted.h + // built/yt/yotta_modules/microbit-dal/inc/types/MicroBitImage.h + // built/yt/yotta_modules/microbit-dal/inc/types/PacketBuffer.h + // built/yt/yotta_modules/microbit-dal/inc/types/RefCounted.h } diff --git a/libs/core/pxt.cpp b/libs/core/pxt.cpp new file mode 100644 index 00000000..4f6188d4 --- /dev/null +++ b/libs/core/pxt.cpp @@ -0,0 +1,472 @@ +#include "pxt.h" +#include + +MicroBit uBit; + +namespace pxt { + int incr(uint32_t e) + { + if (e) { + if (hasVTable(e)) + ((RefObject*)e)->ref(); + else + ((RefCounted*)e)->incr(); + } + return e; + } + + void decr(uint32_t e) + { + if (e) { + if (hasVTable(e)) + ((RefObject*)e)->unref(); + else + ((RefCounted*)e)->decr(); + } + } + + Action mkAction(int reflen, int totallen, int startptr) + { + check(0 <= reflen && reflen <= totallen, ERR_SIZE, 1); + check(reflen <= totallen && totallen <= 255, ERR_SIZE, 2); + check(bytecode[startptr] == 0xffff, ERR_INVALID_BINARY_HEADER, 3); + check(bytecode[startptr + 1] == 0, ERR_INVALID_BINARY_HEADER, 4); + + uint32_t tmp = (uint32_t)&bytecode[startptr]; + + if (totallen == 0) { + return tmp; // no closure needed + } + + void *ptr = ::operator new(sizeof(RefAction) + totallen * sizeof(uint32_t)); + RefAction *r = new (ptr) RefAction(); + r->len = totallen; + r->reflen = reflen; + r->func = (ActionCB)((tmp + 4) | 1); + memset(r->fields, 0, r->len * sizeof(uint32_t)); + + return (Action)r; + } + + uint32_t runAction3(Action a, int arg0, int arg1, int arg2) + { + if (hasVTable(a)) + return ((RefAction*)a)->runCore(arg0, arg1, arg2); + else { + check(*(uint16_t*)a == 0xffff, ERR_INVALID_BINARY_HEADER, 4); + return ((ActionCB)((a + 4) | 1))(NULL, arg0, arg1, arg2); + } + } + + uint32_t runAction2(Action a, int arg0, int arg1) + { + return runAction3(a, arg0, arg1, 0); + } + + uint32_t runAction1(Action a, int arg0) + { + return runAction3(a, arg0, 0, 0); + } + + uint32_t runAction0(Action a) + { + return runAction3(a, 0, 0, 0); + } + + RefRecord* mkClassInstance(int vtableOffset) + { + VTable *vtable = (VTable*)&bytecode[vtableOffset]; + + intcheck(vtable->methods[0] == &RefRecord_destroy, ERR_SIZE, 3); + intcheck(vtable->methods[1] == &RefRecord_print, ERR_SIZE, 4); + + void *ptr = ::operator new(vtable->numbytes); + RefRecord *r = new (ptr) RefRecord(PXT_VTABLE_TO_INT(vtable)); + memset(r->fields, 0, vtable->numbytes - sizeof(RefRecord)); + return r; + } + + uint32_t RefRecord::ld(int idx) + { + //intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 1); + return fields[idx]; + } + + uint32_t RefRecord::ldref(int idx) + { + //printf("LD %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx); + //intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 2); + uint32_t tmp = fields[idx]; + incr(tmp); + return tmp; + } + + void RefRecord::st(int idx, uint32_t v) + { + //intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 3); + fields[idx] = v; + } + + void RefRecord::stref(int idx, uint32_t v) + { + //printf("ST %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx); + //intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 4); + decr(fields[idx]); + fields[idx] = v; + } + + void RefObject::destroy() { + ((RefObjectMethod)getVTable()->methods[0])(this); + delete this; + } + + void RefObject::print() { + ((RefObjectMethod)getVTable()->methods[1])(this); + } + + void RefRecord_destroy(RefRecord *r) { + auto tbl = r->getVTable(); + uint8_t *refmask = (uint8_t*)&tbl->methods[tbl->userdata & 0xff]; + int len = (tbl->numbytes >> 2) - 1; + for (int i = 0; i < len; ++i) { + if (refmask[i]) decr(r->fields[i]); + r->fields[i] = 0; + } + } + + void RefRecord_print(RefRecord *r) + { + printf("RefRecord %p r=%d size=%d bytes\n", r, r->refcnt, r->getVTable()->numbytes); + } + + void RefCollection::push(uint32_t x) { + if (isRef()) incr(x); + data.push_back(x); + } + + uint32_t RefCollection::getAt(int x) { + if (in_range(x)) { + uint32_t tmp = data.at(x); + if (isRef()) incr(tmp); + return tmp; + } + else { + error(ERR_OUT_OF_BOUNDS); + return 0; + } + } + + void RefCollection::removeAt(int x) { + if (!in_range(x)) + return; + + if (isRef()) decr(data.at(x)); + data.erase(data.begin()+x); + } + + void RefCollection::setAt(int x, uint32_t y) { + if (!in_range(x)) + return; + + if (isRef()) { + decr(data.at(x)); + incr(y); + } + data.at(x) = y; + } + + int RefCollection::indexOf(uint32_t x, int start) { + if (!in_range(start)) + return -1; + + if (isString()) { + StringData *xx = (StringData*)x; + for (uint32_t i = start; i < data.size(); ++i) { + StringData *ee = (StringData*)data.at(i); + if (xx->len == ee->len && memcmp(xx->data, ee->data, xx->len) == 0) + return (int)i; + } + } else { + for (uint32_t i = start; i < data.size(); ++i) + if (data.at(i) == x) + return (int)i; + } + + return -1; + } + + int RefCollection::removeElement(uint32_t x) { + int idx = indexOf(x, 0); + if (idx >= 0) { + removeAt(idx); + return 1; + } + return 0; + } + + namespace Coll0 { + PXT_VTABLE_BEGIN(RefCollection, 0, 0) + PXT_VTABLE_END + } + namespace Coll1 { + PXT_VTABLE_BEGIN(RefCollection, 1, 0) + PXT_VTABLE_END + } + namespace Coll3 { + PXT_VTABLE_BEGIN(RefCollection, 3, 0) + PXT_VTABLE_END + } + + RefCollection::RefCollection(uint16_t flags) : RefObject(0) { + switch (flags) { + case 0: + vtable = PXT_VTABLE_TO_INT(&Coll0::RefCollection_vtable); + break; + case 1: + vtable = PXT_VTABLE_TO_INT(&Coll1::RefCollection_vtable); + break; + case 3: + vtable = PXT_VTABLE_TO_INT(&Coll3::RefCollection_vtable); + break; + default: + error(ERR_SIZE); + break; + } + } + + void RefCollection::destroy() + { + if (this->isRef()) + for (uint32_t i = 0; i < this->data.size(); ++i) { + decr(this->data[i]); + this->data[i] = 0; + } + this->data.resize(0); + } + + void RefCollection::print() + { + printf("RefCollection %p r=%d flags=%d size=%d [%p, ...]\n", this, refcnt, getFlags(), data.size(), data.size() > 0 ? data[0] : 0); + } + + PXT_VTABLE_CTOR(RefAction) {} + + // fields[] contain captured locals + void RefAction::destroy() + { + for (int i = 0; i < this->reflen; ++i) { + decr(fields[i]); + fields[i] = 0; + } + } + + void RefAction::print() + { + printf("RefAction %p r=%d pc=0x%lx size=%d (%d refs)\n", this, refcnt, (const uint8_t*)func - (const uint8_t*)bytecode, len, reflen); + } + + void RefLocal::print() + { + printf("RefLocal %p r=%d v=%d\n", this, refcnt, v); + } + + void RefLocal::destroy() + { + } + + PXT_VTABLE_CTOR(RefLocal) { + v = 0; + } + + PXT_VTABLE_CTOR(RefRefLocal) { + v = 0; + } + + void RefRefLocal::print() + { + printf("RefRefLocal %p r=%d v=%p\n", this, refcnt, (void*)v); + } + + void RefRefLocal::destroy() + { + decr(v); + } + + PXT_VTABLE_BEGIN(RefMap, 0, RefMapMarker) + PXT_VTABLE_END + RefMap::RefMap() : PXT_VTABLE_INIT(RefMap) {} + + void RefMap::destroy() { + for (unsigned i = 0; i < data.size(); ++i) { + if (data[i].key & 1) { + decr(data[i].val); + } + data[i].val = 0; + } + data.resize(0); + } + + int RefMap::findIdx(uint32_t key) { + for (unsigned i = 0; i < data.size(); ++i) { + if (data[i].key >> 1 == key) + return i; + } + return -1; + } + + void RefMap::print() + { + printf("RefMap %p r=%d size=%d\n", this, refcnt, data.size()); + } + + +#ifdef DEBUG_MEMLEAKS + std::set allptrs; + void debugMemLeaks() + { + printf("LIVE POINTERS:\n"); + for(std::set::iterator itr = allptrs.begin();itr!=allptrs.end();itr++) + { + (*itr)->print(); + } + printf("\n"); + } +#else + void debugMemLeaks() {} +#endif + + + // --------------------------------------------------------------------------- + // An adapter for the API expected by the run-time. + // --------------------------------------------------------------------------- + + map, Action> handlersMap; + + MicroBitEvent lastEvent; + + // We have the invariant that if [dispatchEvent] is registered against the DAL + // for a given event, then [handlersMap] contains a valid entry for that + // event. + void dispatchEvent(MicroBitEvent e) { + + lastEvent = e; + + Action curr = handlersMap[{ e.source, e.value }]; + if (curr) + runAction1(curr, e.value); + + curr = handlersMap[{ e.source, MICROBIT_EVT_ANY }]; + if (curr) + runAction1(curr, e.value); + } + + void registerWithDal(int id, int event, Action a) { + Action prev = handlersMap[{ id, event }]; + if (prev) + decr(prev); + else + uBit.messageBus.listen(id, event, dispatchEvent); + incr(a); + handlersMap[{ id, event }] = a; + } + + void fiberDone(void *a) + { + decr((Action)a); + release_fiber(); + } + + + void runInBackground(Action a) { + if (a != 0) { + incr(a); + create_fiber((void(*)(void*))runAction0, (void*)a, fiberDone); + } + } + + + void error(ERROR code, int subcode) + { + printf("Error: %d [%d]\n", code, subcode); + uBit.panic(42); + } + + uint16_t *bytecode; + uint32_t *globals; + int numGlobals; + + uint32_t *allocate(uint16_t sz) + { + uint32_t *arr = new uint32_t[sz]; + memset(arr, 0, sz * 4); + return arr; + } + + void checkStr(bool cond, const char *msg) + { + if (!cond) { + while (true) { + uBit.display.scroll(msg, 100); + uBit.sleep(100); + } + } + } + + int templateHash() + { + return ((int*)bytecode)[4]; + } + + int programHash() + { + return ((int*)bytecode)[6]; + } + + int getNumGlobals() + { + return bytecode[16]; + } + + void exec_binary(int32_t *pc) + { + // XXX re-enable once the calibration code is fixed and [editor/embedded.ts] + // properly prepends a call to [internal_main]. + // ::touch_develop::internal_main(); + + // unique group for radio based on source hash + // ::touch_develop::micro_bit::radioDefaultGroup = programHash(); + + // repeat error 4 times and restart as needed + microbit_panic_timeout(4); + + int32_t ver = *pc++; + checkStr(ver == 0x4209, ":( Bad runtime version"); + + bytecode = *((uint16_t**)pc++); // the actual bytecode is here + globals = allocate(getNumGlobals()); + + // just compare the first word + checkStr(((uint32_t*)bytecode)[0] == 0x923B8E70 && + templateHash() == *pc, + ":( Failed partial flash"); + + uint32_t startptr = (uint32_t)bytecode; + startptr += 48; // header + startptr |= 1; // Thumb state + + ((uint32_t (*)())startptr)(); + +#ifdef DEBUG_MEMLEAKS + pxt::debugMemLeaks(); +#endif + + return; + } + + void start() + { + exec_binary((int32_t*)functionsAndBytecode); + } +} + +// vim: ts=2 sw=2 expandtab diff --git a/libs/core/pxt.h b/libs/core/pxt.h new file mode 100644 index 00000000..9ecf2332 --- /dev/null +++ b/libs/core/pxt.h @@ -0,0 +1,333 @@ +#ifndef __PXT_H +#define __PXT_H + +// #define DEBUG_MEMLEAKS 1 + +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#include "MicroBit.h" +#include "MicroBitImage.h" +#include "ManagedString.h" +#include "ManagedType.h" + +#define printf(...) uBit.serial.printf(__VA_ARGS__) +// #define printf(...) + +#define intcheck(...) check(__VA_ARGS__) +//#define intcheck(...) do {} while (0) + +#include +#include +#include +#include + +#ifdef DEBUG_MEMLEAKS +#include +#endif + +extern MicroBit uBit; + +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(); + 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 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 + { + public: + uint16_t refcnt; + uint16_t vtable; + + RefObject(uint16_t vt) + { + refcnt = 2; + vtable = vt; +#ifdef DEBUG_MEMLEAKS + allptrs.insert(this); +#endif + } + + inline VTable *getVTable() { + return (VTable*)(vtable << vtableShift); + } + + void destroy(); + void print(); + + // Call to disable pointer tracking on the current instance (in destructor or some other hack) + inline void untrack() { +#ifdef DEBUG_MEMLEAKS + allptrs.erase(this); +#endif + } + + // Increment/decrement the ref-count. Decrementing to zero deletes the current object. + inline void ref() + { + check(refcnt > 0, ERR_REF_DELETED); + //printf("INCR "); this->print(); + refcnt += 2; + } + + inline void unref() + { + //printf("DECR "); this->print(); + refcnt -= 2; + if (refcnt == 0) { + destroy(); + } + } + }; + + // A ref-counted collection of either primitive or ref-counted objects (String, Image, + // user-defined record, another collection) + class RefCollection + : public RefObject + { + 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; } + + std::vector data; + + RefCollection(uint16_t f); + + inline bool in_range(int x) { + return (0 <= x && x < (int)data.size()); + } + + inline int length() { return data.size(); } + + void destroy(); + void print(); + + void push(uint32_t x); + uint32_t getAt(int x); + void removeAt(int x); + void setAt(int x, uint32_t y); + 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 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(); + }; +} + +// 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) + +#endif + +// vim: ts=2 sw=2 expandtab diff --git a/libs/core/pxt.json b/libs/core/pxt.json index d2c46f73..ff6099ae 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -4,6 +4,10 @@ "installedVersion": "tsmdvf", "files": [ "README.md", + "ManagedBuffer.cpp", + "ManagedBuffer.h", + "pxt.cpp", + "pxt.h", "dal.d.ts", "enums.d.ts", "shims.d.ts", diff --git a/pxtarget.json b/pxtarget.json index 249c1491..48bdf930 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -160,10 +160,10 @@ }, "compileService": { "yottaTarget": "bbc-microbit-classic-gcc", - "yottaCorePackage": "pxt-microbit-core", - "githubCorePackage": "microsoft/pxt-microbit-core", - "gittag": "v0.5.1", - "serviceId": "ws" + "yottaCorePackage": "microbit", + "githubCorePackage": "lancaster-university/microbit", + "gittag": "v2.0.0-rc6", + "serviceId": "microbit" }, "serial": { "manufacturerFilter": "^mbed$", From e0c016fbf4308dbcd73fd41476bf753e1ed37556 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 29 Nov 2016 15:15:22 -0800 Subject: [PATCH 5/6] moving definition out of ksbit.h --- libs/core/ksbit.h | 4 ---- libs/core/pxt.h | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/core/ksbit.h b/libs/core/ksbit.h index f1d3f4b5..e182bdee 100644 --- a/libs/core/ksbit.h +++ b/libs/core/ksbit.h @@ -6,7 +6,3 @@ MicroBitPin *getPin(int id); typedef ImageData* Image; typedef BufferData* Buffer; -namespace pxt { - uint32_t programSize(); - uint32_t afterProgramPage(); -} diff --git a/libs/core/pxt.h b/libs/core/pxt.h index 9ecf2332..46c923ab 100644 --- a/libs/core/pxt.h +++ b/libs/core/pxt.h @@ -61,6 +61,8 @@ namespace pxt { uint32_t *allocate(uint16_t sz); int templateHash(); int programHash(); + uint32_t programSize(); + uint32_t afterProgramPage(); int getNumGlobals(); RefRecord* mkClassInstance(int vtableOffset); From 19fb5ecf01ddde10af87565908b4e9be7bdd53f8 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 29 Nov 2016 21:35:26 -0800 Subject: [PATCH 6/6] merging ksbit.h into pxt.h --- libs/core/basic.cpp | 2 +- libs/core/buffer.cpp | 2 +- libs/core/control.cpp | 2 +- libs/core/core.cpp | 2 +- libs/core/images.cpp | 2 +- libs/core/input.cpp | 2 +- libs/core/ksbit.h | 8 -------- libs/core/led.cpp | 2 +- libs/core/pins.cpp | 2 +- libs/core/pxt.h | 6 ++++++ libs/core/pxt.json | 1 - libs/core/serial.cpp | 2 +- 12 files changed, 15 insertions(+), 18 deletions(-) delete mode 100644 libs/core/ksbit.h diff --git a/libs/core/basic.cpp b/libs/core/basic.cpp index 44c577ba..8ee09b4a 100644 --- a/libs/core/basic.cpp +++ b/libs/core/basic.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" /** diff --git a/libs/core/buffer.cpp b/libs/core/buffer.cpp index b0ea48a2..1ccb5813 100644 --- a/libs/core/buffer.cpp +++ b/libs/core/buffer.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" // keep in sync with github/pxt/pxtsim/libgeneric.ts enum class NumberFormat { diff --git a/libs/core/control.cpp b/libs/core/control.cpp index 13f5543c..dbf50d5b 100644 --- a/libs/core/control.cpp +++ b/libs/core/control.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" /** * How to create the event. diff --git a/libs/core/core.cpp b/libs/core/core.cpp index 574b73f0..30a01639 100644 --- a/libs/core/core.cpp +++ b/libs/core/core.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" #include diff --git a/libs/core/images.cpp b/libs/core/images.cpp index d1e8bb28..15fa5fc1 100644 --- a/libs/core/images.cpp +++ b/libs/core/images.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" /** * Creation, manipulation and display of LED images. diff --git a/libs/core/input.cpp b/libs/core/input.cpp index 5e6a7f11..e1d366aa 100644 --- a/libs/core/input.cpp +++ b/libs/core/input.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" enum class Button { A = MICROBIT_ID_BUTTON_A, diff --git a/libs/core/ksbit.h b/libs/core/ksbit.h deleted file mode 100644 index e182bdee..00000000 --- a/libs/core/ksbit.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "pxt.h" -#include "ManagedBuffer.h" - -using namespace pxt; -MicroBitPin *getPin(int id); -typedef ImageData* Image; -typedef BufferData* Buffer; - diff --git a/libs/core/led.cpp b/libs/core/led.cpp index 457dbf64..a0046c65 100644 --- a/libs/core/led.cpp +++ b/libs/core/led.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" enum class DisplayMode_ { //% block="black and white" diff --git a/libs/core/pins.cpp b/libs/core/pins.cpp index bdc7a9e1..c5c2aa94 100644 --- a/libs/core/pins.cpp +++ b/libs/core/pins.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" enum class DigitalPin { P0 = MICROBIT_ID_IO_P0, diff --git a/libs/core/pxt.h b/libs/core/pxt.h index 46c923ab..182b7621 100644 --- a/libs/core/pxt.h +++ b/libs/core/pxt.h @@ -9,6 +9,7 @@ #include "MicroBitImage.h" #include "ManagedString.h" #include "ManagedType.h" +#include "ManagedBuffer.h" #define printf(...) uBit.serial.printf(__VA_ARGS__) // #define printf(...) @@ -295,6 +296,11 @@ namespace pxt { }; } +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. // diff --git a/libs/core/pxt.json b/libs/core/pxt.json index ff6099ae..b79d7634 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -12,7 +12,6 @@ "enums.d.ts", "shims.d.ts", "pxt-core.d.ts", - "ksbit.h", "core.cpp", "pxt-helpers.ts", "helpers.ts", diff --git a/libs/core/serial.cpp b/libs/core/serial.cpp index 95e7bf7e..cd89aa8b 100644 --- a/libs/core/serial.cpp +++ b/libs/core/serial.cpp @@ -1,4 +1,4 @@ -#include "ksbit.h" +#include "pxt.h" enum SerialPin { P0 = MICROBIT_ID_IO_P0,