support for buffer packet type (#608)
* support for buffer packet type * updated description * updated signature * added note on json encoding * adding sendNumbers * cleanup * removing 'sendnumbers'
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "radio": "Communicate data using radio packets",
 | 
			
		||||
  "radio.Packet.receivedBuffer": "The buffer payload if a buffer was sent in this packet\nor the empty buffer",
 | 
			
		||||
  "radio.Packet.receivedNumber": "The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``)\nor 0 if this packet did not contain a number.",
 | 
			
		||||
  "radio.Packet.receivedString": "The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``)\nor the empty string if this packet did not contain a string.",
 | 
			
		||||
  "radio.Packet.serial": "The serial number of the sender of the packet or 0 if the sender did not sent their serial number.",
 | 
			
		||||
@@ -9,11 +10,13 @@
 | 
			
		||||
  "radio.onDataReceived": "Registers code to run when a packet is received over radio.",
 | 
			
		||||
  "radio.receiveNumber": "Reads the next packet from the radio queue and returns the packet's number\npayload or 0 if the packet did not contain a number.",
 | 
			
		||||
  "radio.receiveString": "Reads the next packet from the radio queue and returns the packet's string\npayload or the empty string if the packet did not contain a string.",
 | 
			
		||||
  "radio.receivedBuffer": "Returns the buffer payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.",
 | 
			
		||||
  "radio.receivedNumber": "Returns the number payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not\ncontain a number.",
 | 
			
		||||
  "radio.receivedSerial": "Returns the serial number of the sender micro:bit from the last packet taken\nfrom the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if\nthat packet did not send a serial number.",
 | 
			
		||||
  "radio.receivedSignalStrength": "Gets the received signal strength indicator (RSSI) from the last packet taken\nfrom the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.\nnamespace=radio",
 | 
			
		||||
  "radio.receivedString": "Returns the string payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.",
 | 
			
		||||
  "radio.receivedTime": "Returns the system time of the sender micro:bit at the moment when it sent the\nlast packet taken from the radio queue (via ``receiveNumber``,\n``receiveString``, etc).",
 | 
			
		||||
  "radio.sendBuffer": "Broadcasts a buffer (up to 19 bytes long) along with the device serial number\nand running time to any connected micro:bit in the group.",
 | 
			
		||||
  "radio.sendNumber": "Broadcasts a number over radio to any connected micro:bit in the group.",
 | 
			
		||||
  "radio.sendString": "Broadcasts a string along with the device serial number\nand running time to any connected micro:bit in the group.",
 | 
			
		||||
  "radio.sendValue": "Broadcasts a name / value pair along with the device serial number\nand running time to any connected micro:bit in the group.",
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,9 @@ using namespace pxt;
 | 
			
		||||
// payload: string length (9), string (10 ... 28)
 | 
			
		||||
#define PACKET_TYPE_STRING 2
 | 
			
		||||
 | 
			
		||||
// payload: buffer length (9), buffer (10 ... 28)
 | 
			
		||||
#define PACKET_TYPE_BUFFER 3
 | 
			
		||||
 | 
			
		||||
//% color=270 weight=96 icon="\uf012"
 | 
			
		||||
namespace radio {
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +42,8 @@ namespace radio {
 | 
			
		||||
    uint32_t time;
 | 
			
		||||
    uint32_t serial;
 | 
			
		||||
    int value;
 | 
			
		||||
    StringData* msg;
 | 
			
		||||
    StringData* msg; // may be NULL before first packet
 | 
			
		||||
    BufferData* bufMsg; // may be NULL before first packet
 | 
			
		||||
 | 
			
		||||
    int radioEnable() {
 | 
			
		||||
        int r = uBit.radio.enable();
 | 
			
		||||
@@ -92,7 +96,7 @@ namespace radio {
 | 
			
		||||
        uint8_t len = min(maxLength, buf[0]);
 | 
			
		||||
 | 
			
		||||
        if (len) {
 | 
			
		||||
            char name[maxLength + 1];
 | 
			
		||||
            char name[len + 1];
 | 
			
		||||
            memcpy(name, buf + 1, len);
 | 
			
		||||
            name[len] = 0;
 | 
			
		||||
            return ManagedString(name).leakData();
 | 
			
		||||
@@ -100,16 +104,45 @@ namespace radio {
 | 
			
		||||
        return ManagedString().leakData();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void writePacketAsJSON(uint8_t tp, int v, int s, int t, StringData* m) {
 | 
			
		||||
    uint8_t copyBufferValue(uint8_t* buf, BufferData* data, uint8_t maxLength) {
 | 
			
		||||
        ManagedBuffer s(data);
 | 
			
		||||
        uint8_t len = min(maxLength, s.length());
 | 
			
		||||
 | 
			
		||||
        // One byte for length of the buffer
 | 
			
		||||
        buf[0] = len;
 | 
			
		||||
        if (len > 0) {
 | 
			
		||||
            memcpy(buf + 1, s.getBytes(), len);
 | 
			
		||||
        }
 | 
			
		||||
        return len + 1;
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    BufferData* 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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void writePacketAsJSON(uint8_t tp, int v, int s, int t, StringData* m, BufferData* b) {
 | 
			
		||||
        // Convert the packet to JSON and send over serial
 | 
			
		||||
        uBit.serial.send("{");
 | 
			
		||||
        uBit.serial.send("\"t\":");
 | 
			
		||||
        uBit.serial.send(t);
 | 
			
		||||
        uBit.serial.send(",\"s\":");
 | 
			
		||||
        uBit.serial.send(s);
 | 
			
		||||
        if (tp == PACKET_TYPE_STRING || tp == PACKET_TYPE_VALUE) {
 | 
			
		||||
        if ((tp == PACKET_TYPE_STRING || tp == PACKET_TYPE_VALUE) && NULL != m) {
 | 
			
		||||
            uBit.serial.send(",\"n\":\"");
 | 
			
		||||
            uBit.serial.send(m);
 | 
			
		||||
            uBit.serial.send(ManagedString(m));
 | 
			
		||||
            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("\"");
 | 
			
		||||
        }
 | 
			
		||||
        if (tp == PACKET_TYPE_NUMBER || tp == PACKET_TYPE_VALUE) {
 | 
			
		||||
@@ -131,28 +164,32 @@ namespace radio {
 | 
			
		||||
        uint8_t tp;
 | 
			
		||||
        int t;
 | 
			
		||||
        int s;
 | 
			
		||||
        int v;
 | 
			
		||||
        StringData* m;
 | 
			
		||||
 | 
			
		||||
        int v = 0;
 | 
			
		||||
        StringData* m = NULL;
 | 
			
		||||
        BufferData* b = NULL;
 | 
			
		||||
 | 
			
		||||
        memcpy(&tp, buf, 1);
 | 
			
		||||
        memcpy(&t, buf + 1, 4);
 | 
			
		||||
        memcpy(&s, buf + 5, 4);
 | 
			
		||||
 | 
			
		||||
        if (tp == PACKET_TYPE_STRING) {
 | 
			
		||||
            v = 0;
 | 
			
		||||
            m = getStringValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1);
 | 
			
		||||
        }
 | 
			
		||||
        else if (tp == PACKET_TYPE_BUFFER) {
 | 
			
		||||
            b = getBufferValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            memcpy(&v, buf + 9, 4);
 | 
			
		||||
            if (tp == PACKET_TYPE_VALUE) {
 | 
			
		||||
                m = getStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_NAME_LENGTH);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                m = ManagedString().leakData();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (NULL == m)
 | 
			
		||||
            m = ManagedString().leakData();
 | 
			
		||||
        if (NULL == b)
 | 
			
		||||
            b = ManagedBuffer().leakData();
 | 
			
		||||
 | 
			
		||||
        if (!writeToSerial) {
 | 
			
		||||
            // Refresh global packet
 | 
			
		||||
            packet = p;
 | 
			
		||||
@@ -161,9 +198,10 @@ namespace radio {
 | 
			
		||||
            serial = s;
 | 
			
		||||
            value = v;
 | 
			
		||||
            msg = m;
 | 
			
		||||
            bufMsg = b;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            writePacketAsJSON(tp, v, s, t, m);
 | 
			
		||||
            writePacketAsJSON(tp, v, s, t, m, b);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -217,7 +255,7 @@ namespace radio {
 | 
			
		||||
    //% weight=58
 | 
			
		||||
    //% blockId=radio_datagram_send_string block="radio send string %msg"
 | 
			
		||||
    void sendString(StringData* msg) {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return;
 | 
			
		||||
 | 
			
		||||
        uint8_t buf[32];
 | 
			
		||||
        memset(buf, 0, 32);
 | 
			
		||||
@@ -228,6 +266,26 @@ namespace radio {
 | 
			
		||||
        uBit.radio.datagram.send(buf, PACKET_PREFIX_LENGTH + stringLen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Broadcasts a buffer (up to 19 bytes long) along with the device serial number
 | 
			
		||||
     * and running time to any connected micro:bit in the group.
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/send-buffer
 | 
			
		||||
    //% weight=57
 | 
			
		||||
    //% advanced=true
 | 
			
		||||
    void sendBuffer(Buffer msg) {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return;
 | 
			
		||||
 | 
			
		||||
        uint8_t buf[32];
 | 
			
		||||
        memset(buf, 0, 32);
 | 
			
		||||
 | 
			
		||||
        setPacketPrefix(buf, PACKET_TYPE_BUFFER);
 | 
			
		||||
        int bufLen = copyBufferValue(buf + PACKET_PREFIX_LENGTH, msg, MAX_PAYLOAD_LENGTH - 1);
 | 
			
		||||
 | 
			
		||||
        uBit.radio.datagram.send(buf, PACKET_PREFIX_LENGTH + bufLen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Reads the next packet from the radio queue and and writes it to serial
 | 
			
		||||
    * as JSON.
 | 
			
		||||
@@ -251,7 +309,7 @@ namespace radio {
 | 
			
		||||
    //% advanced=true
 | 
			
		||||
    void writeReceivedPacketToSerial() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
			
		||||
        writePacketAsJSON(type, value, (int) serial, (int) time, msg);
 | 
			
		||||
        writePacketAsJSON(type, value, (int) serial, (int) time, msg, bufMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -381,10 +439,21 @@ namespace radio {
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/received-string
 | 
			
		||||
    StringData* receivedString() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK) return ManagedString().leakData();
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return ManagedString().leakData();
 | 
			
		||||
        return msg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the buffer payload from the last packet taken from the radio queue
 | 
			
		||||
     * (via ``receiveNumber``, ``receiveString``, etc) or the empty string if that
 | 
			
		||||
     * packet did not contain a string.
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/received-buffer
 | 
			
		||||
    Buffer receivedBuffer() {
 | 
			
		||||
        if (radioEnable() != MICROBIT_OK || NULL == bufMsg) return ManagedBuffer().leakData();
 | 
			
		||||
        return bufMsg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the system time of the sender micro:bit at the moment when it sent the
 | 
			
		||||
     * last packet taken from the radio queue (via ``receiveNumber``,
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,11 @@ namespace radio {
 | 
			
		||||
         * or the empty string if this packet did not contain a string.
 | 
			
		||||
         */
 | 
			
		||||
        public receivedString: string;
 | 
			
		||||
        /**
 | 
			
		||||
         * The buffer payload if a buffer was sent in this packet
 | 
			
		||||
         * or the empty buffer
 | 
			
		||||
         */
 | 
			
		||||
        public receivedBuffer: Buffer;
 | 
			
		||||
        /**
 | 
			
		||||
         * The system time of the sender of the packet at the time the packet was sent.
 | 
			
		||||
         */
 | 
			
		||||
@@ -45,6 +50,7 @@ namespace radio {
 | 
			
		||||
            packet.time = receivedTime();
 | 
			
		||||
            packet.serial = receivedSerial();
 | 
			
		||||
            packet.receivedString = receivedString();
 | 
			
		||||
            packet.receivedBuffer = receivedBuffer();
 | 
			
		||||
            packet.signal = receivedSignalStrength();
 | 
			
		||||
            cb(packet)
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								libs/radio/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								libs/radio/shims.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -33,6 +33,15 @@ declare namespace radio {
 | 
			
		||||
    //% blockId=radio_datagram_send_string block="radio send string %msg" shim=radio::sendString
 | 
			
		||||
    function sendString(msg: string): void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Broadcasts a buffer (up to 19 bytes long) along with the device serial number
 | 
			
		||||
     * and running time to any connected micro:bit in the group.
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/send-buffer
 | 
			
		||||
    //% weight=57
 | 
			
		||||
    //% advanced=true shim=radio::sendBuffer
 | 
			
		||||
    function sendBuffer(msg: Buffer): void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads the next packet from the radio queue and and writes it to serial
 | 
			
		||||
     * as JSON.
 | 
			
		||||
@@ -148,6 +157,14 @@ declare namespace radio {
 | 
			
		||||
    //% help=radio/received-string shim=radio::receivedString
 | 
			
		||||
    function receivedString(): string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the buffer payload from the last packet taken from the radio queue
 | 
			
		||||
     * (via ``receiveNumber``, ``receiveString``, etc) or the empty string if that
 | 
			
		||||
     * packet did not contain a string.
 | 
			
		||||
     */
 | 
			
		||||
    //% help=radio/received-buffer shim=radio::receivedBuffer
 | 
			
		||||
    function receivedBuffer(): Buffer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the system time of the sender micro:bit at the moment when it sent the
 | 
			
		||||
     * last packet taken from the radio queue (via ``receiveNumber``,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user