Rewriting the radio in TypeScript (#2000)
* Refactoring radio into the ts * Moving the rest of the radio functionality to the TypeScript * Removing sim implementation of old radio cpp * Adding test script * Removing handler key * Rename internal functions * PR feedback * Refactoring to use event bus
This commit is contained in:
		@@ -1,39 +1,41 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "radio": "Communicate data using radio packets",
 | 
					  "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.receivedBuffer": "The buffer payload if a buffer was sent in this packet\r\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.receivedNumber": "The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``)\r\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.receivedString": "The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``)\r\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.",
 | 
					  "radio.Packet.serial": "The serial number of the sender of the packet or 0 if the sender did not sent their serial number.",
 | 
				
			||||||
  "radio.Packet.signal": "The received signal strength indicator (RSSI) of the packet.",
 | 
					  "radio.Packet.signal": "The received signal strength indicator (RSSI) of the packet.",
 | 
				
			||||||
  "radio.Packet.time": "The system time of the sender of the packet at the time the packet was sent.",
 | 
					  "radio.Packet.time": "The system time of the sender of the packet at the time the packet was sent.",
 | 
				
			||||||
  "radio._packetProperty": "Gets a packet property.",
 | 
					  "radio._packetProperty": "Gets a packet property.",
 | 
				
			||||||
  "radio._packetProperty|param|type": "the packet property type, eg: PacketProperty.time",
 | 
					  "radio._packetProperty|param|type": "the packet property type, eg: PacketProperty.time",
 | 
				
			||||||
  "radio.onDataPacketReceived": "Registers code to run when the radio receives a packet. Also takes the\nreceived packet from the radio queue.",
 | 
					  "radio.onDataPacketReceived": "Deprecated. Use onDataReceived() instead\r\nRegisters code to run when the radio receives a packet. Also takes the\r\nreceived packet from the radio queue.",
 | 
				
			||||||
  "radio.onDataReceived": "Registers code to run when a packet is received over radio.",
 | 
					  "radio.onDataReceived": "Registers code to run when a packet is received over radio.",
 | 
				
			||||||
  "radio.onReceivedBuffer": "Registers code to run when the radio receives a buffer.",
 | 
					  "radio.onReceivedBuffer": "Registers code to run when the radio receives a buffer.",
 | 
				
			||||||
  "radio.onReceivedBufferDeprecated": "Registers code to run when the radio receives a buffer. Deprecated, use\nonReceivedBuffer instead.",
 | 
					  "radio.onReceivedBufferDeprecated": "Registers code to run when the radio receives a buffer. Deprecated, use\r\nonReceivedBuffer instead.",
 | 
				
			||||||
  "radio.onReceivedNumber": "Registers code to run when the radio receives a number.",
 | 
					  "radio.onReceivedNumber": "Registers code to run when the radio receives a number.",
 | 
				
			||||||
  "radio.onReceivedNumberDeprecated": "Registers code to run when the radio receives a number. Deprecated, use\nonReceivedNumber instead.",
 | 
					  "radio.onReceivedNumberDeprecated": "Registers code to run when the radio receives a number. Deprecated, use\r\nonReceivedNumber instead.",
 | 
				
			||||||
  "radio.onReceivedString": "Registers code to run when the radio receives a string.",
 | 
					  "radio.onReceivedString": "Registers code to run when the radio receives a string.",
 | 
				
			||||||
  "radio.onReceivedStringDeprecated": "Registers code to run when the radio receives a string. Deprecated, use\nonReceivedString instead.",
 | 
					  "radio.onReceivedStringDeprecated": "Registers code to run when the radio receives a string. Deprecated, use\r\nonReceivedString instead.",
 | 
				
			||||||
  "radio.onReceivedValue": "Registers code to run when the radio receives a key value pair.",
 | 
					  "radio.onReceivedValue": "Registers code to run when the radio receives a key value pair.",
 | 
				
			||||||
  "radio.onReceivedValueDeprecated": "Registers code to run when the radio receives a key value pair. Deprecated, use\nonReceivedValue instead.",
 | 
					  "radio.onReceivedValueDeprecated": "Registers code to run when the radio receives a key value pair. Deprecated, use\r\nonReceivedValue instead.",
 | 
				
			||||||
  "radio.raiseEvent": "Sends an event over radio to neigboring devices",
 | 
					  "radio.raiseEvent": "Sends an event over radio to neigboring devices",
 | 
				
			||||||
  "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.readRawPacket": "Takes the next packet from the radio queue and returns its contents in a Buffer",
 | 
				
			||||||
  "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.receiveNumber": "Reads the next packet from the radio queue and returns the packet's number\r\npayload or 0 if the packet did not contain a number.",
 | 
				
			||||||
  "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.receiveString": "Reads the next packet from the radio queue and returns the packet's string\r\npayload or the empty string if the packet 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.receivedBuffer": "Returns the buffer payload from the last packet taken from the radio queue\r\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\r\npacket did not contain a string.",
 | 
				
			||||||
 | 
					  "radio.receivedNumber": "Returns the number payload from the last packet taken from the radio queue\r\n(via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not\r\ncontain a number.",
 | 
				
			||||||
  "radio.receivedPacket": "Returns properties of the last radio packet received.",
 | 
					  "radio.receivedPacket": "Returns properties of the last radio packet received.",
 | 
				
			||||||
  "radio.receivedPacket|param|type": "the type of property to retrieve from the last packet",
 | 
					  "radio.receivedPacket|param|type": "the type of property to retrieve from the last packet",
 | 
				
			||||||
  "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.receivedSerial": "Returns the serial number of the sender micro:bit from the last packet taken\r\nfrom the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if\r\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.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.receivedString": "Returns the string payload from the last packet taken from the radio queue\r\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\r\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.receivedTime": "Returns the system time of the sender micro:bit at the moment when it sent the\r\nlast packet taken from the radio queue (via ``receiveNumber``,\r\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.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.sendNumber": "Broadcasts a number over radio to any connected micro:bit in the group.",
 | 
				
			||||||
 | 
					  "radio.sendRawPacket": "Sends a raw packet through the radio",
 | 
				
			||||||
  "radio.sendString": "Broadcasts a string along with the device serial number\nand running time 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.",
 | 
					  "radio.sendValue": "Broadcasts a name / value pair along with the device serial number\nand running time to any connected micro:bit in the group. The name can\ninclude no more than 8 characters.",
 | 
				
			||||||
  "radio.sendValue|param|name": "the field name (max 12 characters), eg: \"name\"",
 | 
					  "radio.sendValue|param|name": "the field name (max 8 characters), eg: \"name\"",
 | 
				
			||||||
  "radio.sendValue|param|value": "the numeric value",
 | 
					  "radio.sendValue|param|value": "the numeric value",
 | 
				
			||||||
  "radio.setGroup": "Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.",
 | 
					  "radio.setGroup": "Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.",
 | 
				
			||||||
  "radio.setGroup|param|id": "the group id between ``0`` and ``255``, eg: 1",
 | 
					  "radio.setGroup|param|id": "the group id between ``0`` and ``255``, eg: 1",
 | 
				
			||||||
@@ -42,5 +44,5 @@
 | 
				
			|||||||
  "radio.setTransmitSerialNumber": "Set the radio to transmit the serial number in each message.",
 | 
					  "radio.setTransmitSerialNumber": "Set the radio to transmit the serial number in each message.",
 | 
				
			||||||
  "radio.setTransmitSerialNumber|param|transmit": "value indicating if the serial number is transmitted, eg: true",
 | 
					  "radio.setTransmitSerialNumber|param|transmit": "value indicating if the serial number is transmitted, eg: true",
 | 
				
			||||||
  "radio.writeReceivedPacketToSerial": "Writes the last received packet to serial as JSON. This should be called\nwithin an ``onDataPacketReceived`` callback.",
 | 
					  "radio.writeReceivedPacketToSerial": "Writes the last received packet to serial as JSON. This should be called\nwithin an ``onDataPacketReceived`` callback.",
 | 
				
			||||||
  "radio.writeValueToSerial": "Reads the next packet from the radio queue and and writes it to serial\nas JSON."
 | 
					  "radio.writeValueToSerial": "Reads the next packet from the radio queue and and writes it to serial\r\nas JSON."
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										188
									
								
								libs/radio/deprecated.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								libs/radio/deprecated.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					namespace radio {
 | 
				
			||||||
 | 
					    export class Packet {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``)
 | 
				
			||||||
 | 
					         * or 0 if this packet did not contain a number.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        public receivedNumber: number;
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``)
 | 
				
			||||||
 | 
					         * 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.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        public time: number;
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The serial number of the sender of the packet or 0 if the sender did not sent their serial number.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        public serial: number;
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The received signal strength indicator (RSSI) of the packet.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        public signal: number;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Deprecated. Use onDataReceived() instead
 | 
				
			||||||
 | 
					     * Registers code to run when the radio receives a packet. Also takes the
 | 
				
			||||||
 | 
					     * received packet from the radio queue.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/on-data-packet-received blockHandlerKey="radioreceived" deprecated=true
 | 
				
			||||||
 | 
					    //% mutate=objectdestructuring
 | 
				
			||||||
 | 
					    //% mutateText=Packet
 | 
				
			||||||
 | 
					    //% mutateDefaults="receivedNumber;receivedString:name,receivedNumber:value;receivedString"
 | 
				
			||||||
 | 
					    //% blockId=radio_on_packet block="on radio received" blockGap=8
 | 
				
			||||||
 | 
					    export function onDataPacketReceived(cb: (packet: Packet) => void) {
 | 
				
			||||||
 | 
					        onDataReceived(() => {
 | 
				
			||||||
 | 
					            receiveNumber();
 | 
				
			||||||
 | 
					            const packet = new Packet();
 | 
				
			||||||
 | 
					            packet.receivedNumber = receivedNumber();
 | 
				
			||||||
 | 
					            packet.time = receivedTime();
 | 
				
			||||||
 | 
					            packet.serial = receivedSerial();
 | 
				
			||||||
 | 
					            packet.receivedString = receivedString();
 | 
				
			||||||
 | 
					            packet.receivedBuffer = receivedBuffer();
 | 
				
			||||||
 | 
					            packet.signal = receivedSignalStrength();
 | 
				
			||||||
 | 
					            cb(packet)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Registers code to run when the radio receives a number. Deprecated, use
 | 
				
			||||||
 | 
					     * onReceivedNumber instead.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/on-received-number blockHandlerKey="radioreceived"
 | 
				
			||||||
 | 
					    //% blockId=radio_on_number block="on radio received" blockGap=16
 | 
				
			||||||
 | 
					    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
				
			||||||
 | 
					    export function onReceivedNumberDeprecated(cb: (receivedNumber: number) => void) {
 | 
				
			||||||
 | 
					        onReceivedNumber(cb);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Registers code to run when the radio receives a key value pair. Deprecated, use
 | 
				
			||||||
 | 
					     * onReceivedValue instead.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/on-received-value blockHandlerKey="radioreceived"
 | 
				
			||||||
 | 
					    //% blockId=radio_on_value block="on radio received" blockGap=16
 | 
				
			||||||
 | 
					    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
				
			||||||
 | 
					    export function onReceivedValueDeprecated(cb: (name: string, value: number) => void) {
 | 
				
			||||||
 | 
					        onReceivedValue(cb);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Registers code to run when the radio receives a string. Deprecated, use
 | 
				
			||||||
 | 
					     * onReceivedString instead.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/on-received-string blockHandlerKey="radioreceived"
 | 
				
			||||||
 | 
					    //% blockId=radio_on_string block="on radio received" blockGap=16
 | 
				
			||||||
 | 
					    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
				
			||||||
 | 
					    export function onReceivedStringDeprecated(cb: (receivedString: string) => void) {
 | 
				
			||||||
 | 
					        onReceivedString(cb);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Registers code to run when the radio receives a buffer. Deprecated, use
 | 
				
			||||||
 | 
					     * onReceivedBuffer instead.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/on-received-buffer blockHandlerKey="radioreceived" blockHidden=1
 | 
				
			||||||
 | 
					    //% blockId=radio_on_buffer block="on radio received" blockGap=16
 | 
				
			||||||
 | 
					    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
				
			||||||
 | 
					    export function onReceivedBufferDeprecated(cb: (receivedBuffer: Buffer) => void) {
 | 
				
			||||||
 | 
					        onReceivedBuffer(cb);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Reads the next packet from the radio queue and and writes it to serial
 | 
				
			||||||
 | 
					    * as JSON.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    //% help=radio/write-value-to-serial
 | 
				
			||||||
 | 
					    //% weight=3
 | 
				
			||||||
 | 
					    //% blockId=radio_write_value_serial block="radio write value to serial"
 | 
				
			||||||
 | 
					    //% deprecated=true
 | 
				
			||||||
 | 
					    export function writeValueToSerial() {
 | 
				
			||||||
 | 
					        const p = RadioPacket.getPacket(radio.readRawPacket());
 | 
				
			||||||
 | 
					        writeToSerial(p);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the number payload from the last packet taken from the radio queue
 | 
				
			||||||
 | 
					     * (via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not
 | 
				
			||||||
 | 
					     * contain a number.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/received-number deprecated=1
 | 
				
			||||||
 | 
					    export function receivedNumber(): number {
 | 
				
			||||||
 | 
					        return (lastPacket ? lastPacket.numberPayload : 0) || 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the serial number of the sender micro:bit from the last packet taken
 | 
				
			||||||
 | 
					     * from the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if
 | 
				
			||||||
 | 
					     * that packet did not send a serial number.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/received-serial deprecated=1
 | 
				
			||||||
 | 
					    export function receivedSerial(): number {
 | 
				
			||||||
 | 
					        return lastPacket ? lastPacket.serial : 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns the string 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-string deprecated=1
 | 
				
			||||||
 | 
					    export function receivedString(): string {
 | 
				
			||||||
 | 
					        return (lastPacket ? lastPacket.stringPayload : "") || "";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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 deprecated=1
 | 
				
			||||||
 | 
					    export function receivedBuffer(): Buffer {
 | 
				
			||||||
 | 
					        return (lastPacket ? lastPacket.bufferPayload : null) || control.createBuffer(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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``,
 | 
				
			||||||
 | 
					     * ``receiveString``, etc).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/received-time deprecated=1
 | 
				
			||||||
 | 
					    export function receivedTime(): number {
 | 
				
			||||||
 | 
					        return lastPacket ? lastPacket.time : 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reads the next packet from the radio queue and returns the packet's number
 | 
				
			||||||
 | 
					     * payload or 0 if the packet did not contain a number.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/receive-number
 | 
				
			||||||
 | 
					    //% weight=46
 | 
				
			||||||
 | 
					    //% blockId=radio_datagram_receive block="radio receive number" blockGap=8
 | 
				
			||||||
 | 
					    //% deprecated=true
 | 
				
			||||||
 | 
					    export function receiveNumber(): number {
 | 
				
			||||||
 | 
					        lastPacket = RadioPacket.getPacket(readRawPacket());
 | 
				
			||||||
 | 
					        return receivedNumber();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reads the next packet from the radio queue and returns the packet's string
 | 
				
			||||||
 | 
					     * payload or the empty string if the packet did not contain a string.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8
 | 
				
			||||||
 | 
					    //% weight=44
 | 
				
			||||||
 | 
					    //% help=radio/receive-string
 | 
				
			||||||
 | 
					    //% deprecated=true
 | 
				
			||||||
 | 
					    export function receiveString(): string {
 | 
				
			||||||
 | 
					        lastPacket = RadioPacket.getPacket(readRawPacket());
 | 
				
			||||||
 | 
					        return receivedString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,7 +6,8 @@
 | 
				
			|||||||
        "shims.d.ts",
 | 
					        "shims.d.ts",
 | 
				
			||||||
        "enums.d.ts",
 | 
					        "enums.d.ts",
 | 
				
			||||||
        "radio.cpp",
 | 
					        "radio.cpp",
 | 
				
			||||||
        "radio.ts"
 | 
					        "radio.ts",
 | 
				
			||||||
 | 
					        "deprecated.ts"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "icon": "./static/packages/radio/icon.png",
 | 
					    "icon": "./static/packages/radio/icon.png",
 | 
				
			||||||
    "public": true,
 | 
					    "public": true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,58 +2,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace pxt;
 | 
					using namespace pxt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_FIELD_NAME_LENGTH 12
 | 
					 | 
				
			||||||
#define MAX_FIELD_DOUBLE_NAME_LENGTH 8
 | 
					 | 
				
			||||||
#define MAX_PAYLOAD_LENGTH 20
 | 
					 | 
				
			||||||
#define PACKET_PREFIX_LENGTH 9
 | 
					 | 
				
			||||||
#define VALUE_PACKET_NAME_LEN_OFFSET 13
 | 
					 | 
				
			||||||
#define DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET 17
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Packet Spec:
 | 
					 | 
				
			||||||
// | 0              | 1 ... 4       | 5 ... 8           | 9 ... 28
 | 
					 | 
				
			||||||
// ----------------------------------------------------------------
 | 
					 | 
				
			||||||
// | packet type    | system time   | serial number     | payload
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Serial number defaults to 0 unless enabled by user
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// payload: number (9 ... 12)
 | 
					 | 
				
			||||||
#define PACKET_TYPE_NUMBER 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// payload: number (9 ... 12), name length (13), name (14 ... 26)
 | 
					 | 
				
			||||||
#define PACKET_TYPE_VALUE 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// payload: string length (9), string (10 ... 28)
 | 
					 | 
				
			||||||
#define PACKET_TYPE_STRING 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// payload: buffer length (9), buffer (10 ... 28)
 | 
					 | 
				
			||||||
#define PACKET_TYPE_BUFFER 3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// payload: number (9 ... 16)
 | 
					 | 
				
			||||||
#define PACKET_TYPE_DOUBLE 4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// payload: number (9 ... 16), name length (17), name (18 ... 26)
 | 
					 | 
				
			||||||
#define PACKET_TYPE_DOUBLE_VALUE 5
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//% color=#E3008C weight=96 icon="\uf012"
 | 
					//% color=#E3008C weight=96 icon="\uf012"
 | 
				
			||||||
namespace radio {
 | 
					namespace radio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // -------------------------------------------------------------------------
 | 
					 | 
				
			||||||
    // Radio
 | 
					 | 
				
			||||||
    // -------------------------------------------------------------------------
 | 
					 | 
				
			||||||
    bool radioEnabled = false;
 | 
					    bool radioEnabled = false;
 | 
				
			||||||
    bool transmitSerialNumber = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    PacketBuffer packet;
 | 
					    PacketBuffer packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t type;
 | 
					 | 
				
			||||||
    uint32_t time;
 | 
					 | 
				
			||||||
    uint32_t serial;
 | 
					 | 
				
			||||||
    int ivalue;
 | 
					 | 
				
			||||||
    double dvalue;
 | 
					 | 
				
			||||||
    String msg; // may be NULL before first packet
 | 
					 | 
				
			||||||
    Buffer bufMsg; // may be NULL before first packet
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int radioEnable() {
 | 
					    int radioEnable() {
 | 
				
			||||||
        int r = uBit.radio.enable();
 | 
					        int r = uBit.radio.enable();
 | 
				
			||||||
        if (r != MICROBIT_OK) {
 | 
					        if (r != MICROBIT_OK) {
 | 
				
			||||||
@@ -81,303 +35,23 @@ namespace radio {
 | 
				
			|||||||
        uBit.radio.event.eventReceived(MicroBitEvent(src, value, CREATE_ONLY));
 | 
					        uBit.radio.event.eventReceived(MicroBitEvent(src, value, CREATE_ONLY));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void setPacketPrefix(uint8_t* buf, int type) {
 | 
					 | 
				
			||||||
        // prefix: type (0), time (1..4), serial (5..8)
 | 
					 | 
				
			||||||
        uint32_t t = system_timer_current_time();
 | 
					 | 
				
			||||||
        uint32_t sn = transmitSerialNumber ? microbit_serial_number() : 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        buf[0] = (uint8_t) type;
 | 
					 | 
				
			||||||
        memcpy(buf + 1, &t, 4);
 | 
					 | 
				
			||||||
        memcpy(buf + 5, &sn, 4);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t copyStringValue(uint8_t* buf, String data, uint8_t maxLength) {
 | 
					 | 
				
			||||||
        uint8_t len = min_(maxLength, data->getUTF8Size());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // One byte for length of the string
 | 
					 | 
				
			||||||
        buf[0] = len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (len > 0) {
 | 
					 | 
				
			||||||
            memcpy(buf + 1, data->getUTF8Data(), len);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return len + 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    String getStringValue(uint8_t* buf, uint8_t maxLength) {
 | 
					 | 
				
			||||||
        // First byte is the string length
 | 
					 | 
				
			||||||
        uint8_t len = min_(maxLength, buf[0]);
 | 
					 | 
				
			||||||
        return mkString((char*)buf + 1, len);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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, data->data, len);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return len + 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Buffer getBufferValue(uint8_t* buf, uint8_t maxLength) {
 | 
					 | 
				
			||||||
        // First byte is the buffer length
 | 
					 | 
				
			||||||
        uint8_t len = min_(maxLength, buf[0]);
 | 
					 | 
				
			||||||
        // skip first byte
 | 
					 | 
				
			||||||
        return mkBuffer(buf + 1, len);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void writePacketAsJSON(uint8_t tp, int iv, double dv, int s, int t, String m, Buffer 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) && NULL != m) {
 | 
					 | 
				
			||||||
            uBit.serial.send(",\"n\":\"");
 | 
					 | 
				
			||||||
            uBit.serial.send((uint8_t*)m->getUTF8Data(), m->getUTF8Size());
 | 
					 | 
				
			||||||
            uBit.serial.send("\"");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (tp == PACKET_TYPE_BUFFER && NULL != b) {
 | 
					 | 
				
			||||||
            uBit.serial.send(",\"b\":\"");
 | 
					 | 
				
			||||||
            // TODO: proper base64 encoding
 | 
					 | 
				
			||||||
            uBit.serial.send(b->data, b->length);
 | 
					 | 
				
			||||||
            uBit.serial.send("\"");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (tp == PACKET_TYPE_NUMBER || tp == PACKET_TYPE_VALUE) {
 | 
					 | 
				
			||||||
            uBit.serial.send(",\"v\":");
 | 
					 | 
				
			||||||
            uBit.serial.send(iv);
 | 
					 | 
				
			||||||
        } else if (tp == PACKET_TYPE_DOUBLE || tp == PACKET_TYPE_DOUBLE_VALUE) {
 | 
					 | 
				
			||||||
            uBit.serial.send(",\"v\":");
 | 
					 | 
				
			||||||
            TNumber td = fromDouble(dv);
 | 
					 | 
				
			||||||
            String sd = numops::toString(td);
 | 
					 | 
				
			||||||
            uBit.serial.send((uint8_t*)sd->getUTF8Data(), sd->getUTF8Size());
 | 
					 | 
				
			||||||
            decrRC(sd);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        uBit.serial.send("}\r\n");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Takes a packet from the micro:bit radio queue.
 | 
					     * Takes the next packet from the radio queue and returns its contents in a Buffer
 | 
				
			||||||
     * @param writeToSerial if true, write the received packet to serial without updating the global packet;
 | 
					 | 
				
			||||||
                            if false, update the global packet instead
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void receivePacket(bool writeToSerial) {
 | 
					    //% help=radio/received-packet
 | 
				
			||||||
        PacketBuffer p = uBit.radio.datagram.recv();
 | 
					    Buffer readRawPacket() {
 | 
				
			||||||
 | 
					        if (radioEnable() != MICROBIT_OK) return mkBuffer(NULL, 0);
 | 
				
			||||||
        uint8_t* buf = p.getBytes();
 | 
					        packet = uBit.radio.datagram.recv();
 | 
				
			||||||
        uint8_t tp;
 | 
					        return mkBuffer(packet.getBytes(), packet.length());
 | 
				
			||||||
        int t;
 | 
					 | 
				
			||||||
        int s;
 | 
					 | 
				
			||||||
        int iv = 0;
 | 
					 | 
				
			||||||
        double dv = 0;
 | 
					 | 
				
			||||||
        String m = NULL;
 | 
					 | 
				
			||||||
        Buffer b = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        memcpy(&tp, buf, 1);
 | 
					 | 
				
			||||||
        memcpy(&t, buf + 1, 4);
 | 
					 | 
				
			||||||
        memcpy(&s, buf + 5, 4);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        switch(tp) {
 | 
					 | 
				
			||||||
            case PACKET_TYPE_STRING:
 | 
					 | 
				
			||||||
                m = getStringValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case PACKET_TYPE_BUFFER:
 | 
					 | 
				
			||||||
                b = getBufferValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case PACKET_TYPE_DOUBLE:
 | 
					 | 
				
			||||||
            case PACKET_TYPE_DOUBLE_VALUE:
 | 
					 | 
				
			||||||
                memcpy(&dv, buf + PACKET_PREFIX_LENGTH, sizeof(double));
 | 
					 | 
				
			||||||
                if (tp == PACKET_TYPE_DOUBLE_VALUE) {
 | 
					 | 
				
			||||||
                    m = getStringValue(buf + DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_DOUBLE_NAME_LENGTH);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case PACKET_TYPE_NUMBER:
 | 
					 | 
				
			||||||
            case PACKET_TYPE_VALUE:
 | 
					 | 
				
			||||||
                memcpy(&iv, buf + PACKET_PREFIX_LENGTH, sizeof(int));
 | 
					 | 
				
			||||||
                if (tp == PACKET_TYPE_VALUE) {
 | 
					 | 
				
			||||||
                    m = getStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_NAME_LENGTH);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default: // unknown packet
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (NULL == m)
 | 
					 | 
				
			||||||
            m = mkString("", 0);
 | 
					 | 
				
			||||||
        if (NULL == b)
 | 
					 | 
				
			||||||
            b = mkBuffer(NULL, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!writeToSerial) {
 | 
					 | 
				
			||||||
            // Refresh global packet
 | 
					 | 
				
			||||||
            packet = p;
 | 
					 | 
				
			||||||
            type = tp;
 | 
					 | 
				
			||||||
            time = t;
 | 
					 | 
				
			||||||
            serial = s;
 | 
					 | 
				
			||||||
            ivalue = iv;
 | 
					 | 
				
			||||||
            dvalue = dv;
 | 
					 | 
				
			||||||
            decrRC(msg);
 | 
					 | 
				
			||||||
            decrRC(bufMsg);
 | 
					 | 
				
			||||||
            msg = m;
 | 
					 | 
				
			||||||
            bufMsg = b;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            writePacketAsJSON(tp, iv, dv, s, t, m, b);
 | 
					 | 
				
			||||||
            decrRC(m);
 | 
					 | 
				
			||||||
            decrRC(b);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Broadcasts a number over radio to any connected micro:bit in the group.
 | 
					     * Sends a raw packet through the radio
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/send-number
 | 
					 | 
				
			||||||
    //% weight=60
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_send block="radio send number %value" blockGap=8
 | 
					 | 
				
			||||||
    void sendNumber(TNumber value) {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int iv = toInt(value);
 | 
					 | 
				
			||||||
        double dv = toDouble(value);
 | 
					 | 
				
			||||||
        if (iv == dv) {
 | 
					 | 
				
			||||||
            uint8_t length = PACKET_PREFIX_LENGTH + sizeof(int);
 | 
					 | 
				
			||||||
            uint8_t buf[length];
 | 
					 | 
				
			||||||
            memset(buf, 0, length);
 | 
					 | 
				
			||||||
            setPacketPrefix(buf, PACKET_TYPE_NUMBER);
 | 
					 | 
				
			||||||
            memcpy(buf + PACKET_PREFIX_LENGTH, &iv, sizeof(int));
 | 
					 | 
				
			||||||
            uBit.radio.datagram.send(buf, length);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            uint8_t length = PACKET_PREFIX_LENGTH + sizeof(double);
 | 
					 | 
				
			||||||
            uint8_t buf[length];
 | 
					 | 
				
			||||||
            memset(buf, 0, length);
 | 
					 | 
				
			||||||
            setPacketPrefix(buf, PACKET_TYPE_DOUBLE);
 | 
					 | 
				
			||||||
            memcpy(buf + PACKET_PREFIX_LENGTH, &dv, sizeof(double));
 | 
					 | 
				
			||||||
            uBit.radio.datagram.send(buf, length);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
    * Broadcasts a name / value pair along with the device serial number
 | 
					 | 
				
			||||||
    * and running time to any connected micro:bit in the group. The name can
 | 
					 | 
				
			||||||
    * include no more than 8 characters.
 | 
					 | 
				
			||||||
    * @param name the field name (max 8 characters), eg: "name"
 | 
					 | 
				
			||||||
    * @param value the numeric value
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    //% help=radio/send-value
 | 
					 | 
				
			||||||
    //% weight=59
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8
 | 
					 | 
				
			||||||
    void sendValue(String name, TNumber value) {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint8_t buf[32];
 | 
					 | 
				
			||||||
        memset(buf, 0, 32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int iv = toInt(value);
 | 
					 | 
				
			||||||
        double dv = toDouble(value);
 | 
					 | 
				
			||||||
        if (iv == dv) {
 | 
					 | 
				
			||||||
            setPacketPrefix(buf, PACKET_TYPE_VALUE);
 | 
					 | 
				
			||||||
            memcpy(buf + PACKET_PREFIX_LENGTH, &iv, sizeof(int));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            int stringLen = copyStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_DOUBLE_NAME_LENGTH);
 | 
					 | 
				
			||||||
            uBit.radio.datagram.send(buf, VALUE_PACKET_NAME_LEN_OFFSET + stringLen);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            setPacketPrefix(buf, PACKET_TYPE_DOUBLE_VALUE);
 | 
					 | 
				
			||||||
            memcpy(buf + PACKET_PREFIX_LENGTH, &dv, sizeof(double));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            int stringLen = copyStringValue(buf + DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_NAME_LENGTH);
 | 
					 | 
				
			||||||
            uBit.radio.datagram.send(buf, DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET + stringLen);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Broadcasts a string along with the device serial number
 | 
					 | 
				
			||||||
     * and running time to any connected micro:bit in the group.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/send-string
 | 
					 | 
				
			||||||
    //% weight=58
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_send_string block="radio send string %msg"
 | 
					 | 
				
			||||||
    //% msg.shadowOptions.toString=true
 | 
					 | 
				
			||||||
    void sendString(String msg) {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint8_t buf[32];
 | 
					 | 
				
			||||||
        memset(buf, 0, 32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        setPacketPrefix(buf, PACKET_TYPE_STRING);
 | 
					 | 
				
			||||||
        int stringLen = copyStringValue(buf + PACKET_PREFIX_LENGTH, msg, MAX_PAYLOAD_LENGTH - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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
 | 
					    //% advanced=true
 | 
				
			||||||
    void sendBuffer(Buffer msg) {
 | 
					    void sendRawPacket(Buffer msg) {
 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return;
 | 
					        if (radioEnable() != MICROBIT_OK || NULL == msg) return;
 | 
				
			||||||
 | 
					        uBit.radio.datagram.send(msg->data, msg->length);
 | 
				
			||||||
        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.
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    //% help=radio/write-value-to-serial
 | 
					 | 
				
			||||||
    //% weight=3
 | 
					 | 
				
			||||||
    //% blockId=radio_write_value_serial block="radio write value to serial"
 | 
					 | 
				
			||||||
    //% deprecated=true
 | 
					 | 
				
			||||||
    void writeValueToSerial() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					 | 
				
			||||||
        receivePacket(true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
    * Writes the last received packet to serial as JSON. This should be called
 | 
					 | 
				
			||||||
    * within an ``onDataPacketReceived`` callback.
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    //% help=radio/write-received-packet-to-serial
 | 
					 | 
				
			||||||
    //% weight=3
 | 
					 | 
				
			||||||
    //% blockId=radio_write_packet_serial block="radio write received packet to serial"
 | 
					 | 
				
			||||||
    //% advanced=true
 | 
					 | 
				
			||||||
    void writeReceivedPacketToSerial() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					 | 
				
			||||||
        writePacketAsJSON(type, ivalue, dvalue, (int) serial, (int) time, msg, bufMsg);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    TNumber readNumber() {
 | 
					 | 
				
			||||||
        if (type == PACKET_TYPE_NUMBER || type == PACKET_TYPE_VALUE)
 | 
					 | 
				
			||||||
            return fromInt(ivalue);
 | 
					 | 
				
			||||||
        else if (type == PACKET_TYPE_DOUBLE || type == PACKET_TYPE_DOUBLE_VALUE)
 | 
					 | 
				
			||||||
            return fromDouble(dvalue);
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            return fromInt(0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Reads the next packet from the radio queue and returns the packet's number
 | 
					 | 
				
			||||||
     * payload or 0 if the packet did not contain a number.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/receive-number
 | 
					 | 
				
			||||||
    //% weight=46
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_receive block="radio receive number" blockGap=8
 | 
					 | 
				
			||||||
    //% deprecated=true
 | 
					 | 
				
			||||||
    TNumber receiveNumber()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return 0;
 | 
					 | 
				
			||||||
        receivePacket(false);
 | 
					 | 
				
			||||||
        return readNumber();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -390,23 +64,7 @@ namespace radio {
 | 
				
			|||||||
    void onDataReceived(Action body) {
 | 
					    void onDataReceived(Action body) {
 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					        if (radioEnable() != MICROBIT_OK) return;
 | 
				
			||||||
        registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body);
 | 
					        registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body);
 | 
				
			||||||
        // make sure the receive buffer has a free spot
 | 
					        readRawPacket();
 | 
				
			||||||
        receivePacket(false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Reads the next packet from the radio queue and returns the packet's string
 | 
					 | 
				
			||||||
     * payload or the empty string if the packet did not contain a string.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8
 | 
					 | 
				
			||||||
    //% weight=44
 | 
					 | 
				
			||||||
    //% help=radio/receive-string
 | 
					 | 
				
			||||||
    //% deprecated=true
 | 
					 | 
				
			||||||
    String receiveString() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return mkString("", 0);
 | 
					 | 
				
			||||||
        receivePacket(false);
 | 
					 | 
				
			||||||
        return msg;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -419,7 +77,7 @@ namespace radio {
 | 
				
			|||||||
    //% blockId=radio_datagram_rssi block="radio received signal strength"
 | 
					    //% blockId=radio_datagram_rssi block="radio received signal strength"
 | 
				
			||||||
    //% deprecated=true
 | 
					    //% deprecated=true
 | 
				
			||||||
    int receivedSignalStrength() {
 | 
					    int receivedSignalStrength() {
 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return 0;
 | 
					        if (radioEnable() != MICROBIT_OK || packet == NULL) return 0;
 | 
				
			||||||
        return packet.getRSSI();
 | 
					        return packet.getRSSI();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -449,74 +107,4 @@ namespace radio {
 | 
				
			|||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					        if (radioEnable() != MICROBIT_OK) return;
 | 
				
			||||||
        uBit.radio.setTransmitPower(power);
 | 
					        uBit.radio.setTransmitPower(power);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
    * Set the radio to transmit the serial number in each message.
 | 
					 | 
				
			||||||
    * @param transmit value indicating if the serial number is transmitted, eg: true
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    //% help=radio/set-transmit-serial-number
 | 
					 | 
				
			||||||
    //% weight=8 blockGap=8
 | 
					 | 
				
			||||||
    //% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit"
 | 
					 | 
				
			||||||
    //% advanced=true
 | 
					 | 
				
			||||||
    void setTransmitSerialNumber(bool transmit) {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return;
 | 
					 | 
				
			||||||
        transmitSerialNumber = transmit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns the number payload from the last packet taken from the radio queue
 | 
					 | 
				
			||||||
     * (via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not
 | 
					 | 
				
			||||||
     * contain a number.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/received-number
 | 
					 | 
				
			||||||
    TNumber receivedNumber() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return 0;
 | 
					 | 
				
			||||||
        return readNumber();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns the serial number of the sender micro:bit from the last packet taken
 | 
					 | 
				
			||||||
     * from the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if
 | 
					 | 
				
			||||||
     * that packet did not send a serial number.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/received-serial
 | 
					 | 
				
			||||||
    uint32_t receivedSerial() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return 0;
 | 
					 | 
				
			||||||
        return serial;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns the string 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-string
 | 
					 | 
				
			||||||
    String receivedString() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK || NULL == msg) return mkString("", 0);
 | 
					 | 
				
			||||||
        incrRC(msg);
 | 
					 | 
				
			||||||
        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 mkBuffer(NULL, 0);
 | 
					 | 
				
			||||||
        incrRC(bufMsg);
 | 
					 | 
				
			||||||
        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``,
 | 
					 | 
				
			||||||
     * ``receiveString``, etc).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/received-time
 | 
					 | 
				
			||||||
    uint32_t receivedTime() {
 | 
					 | 
				
			||||||
        if (radioEnable() != MICROBIT_OK) return 0;
 | 
					 | 
				
			||||||
        return time;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,182 +16,121 @@ enum RadioPacketProperty {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
//% color=#E3008C weight=96 icon="\uf012"
 | 
					//% color=#E3008C weight=96 icon="\uf012"
 | 
				
			||||||
namespace radio {
 | 
					namespace radio {
 | 
				
			||||||
    export class Packet {
 | 
					    export const MAKECODE_RADIO_EVT_NUMBER = 10;
 | 
				
			||||||
        /**
 | 
					    export const MAKECODE_RADIO_EVT_STRING = 11;
 | 
				
			||||||
         * The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``)
 | 
					    export const MAKECODE_RADIO_EVT_BUFFER = 12;
 | 
				
			||||||
         * or 0 if this packet did not contain a number.
 | 
					    export const MAKECODE_RADIO_EVT_VALUE = 13;
 | 
				
			||||||
         */
 | 
					
 | 
				
			||||||
        public receivedNumber: number;
 | 
					    const MAX_FIELD_DOUBLE_NAME_LENGTH = 8;
 | 
				
			||||||
        /**
 | 
					    const MAX_PAYLOAD_LENGTH = 20;
 | 
				
			||||||
         * The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``)
 | 
					    const PACKET_PREFIX_LENGTH = 9;
 | 
				
			||||||
         * or the empty string if this packet did not contain a string.
 | 
					    const VALUE_PACKET_NAME_LEN_OFFSET = 13;
 | 
				
			||||||
         */
 | 
					    const DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET = 17;
 | 
				
			||||||
        public receivedString: string;
 | 
					
 | 
				
			||||||
        /**
 | 
					    // Packet Spec:
 | 
				
			||||||
         * The buffer payload if a buffer was sent in this packet
 | 
					    // | 0              | 1 ... 4       | 5 ... 8           | 9 ... 28
 | 
				
			||||||
         * or the empty buffer
 | 
					    // ----------------------------------------------------------------
 | 
				
			||||||
         */
 | 
					    // | packet type    | system time   | serial number     | payload
 | 
				
			||||||
        public receivedBuffer: Buffer;
 | 
					    //
 | 
				
			||||||
        /**
 | 
					    // Serial number defaults to 0 unless enabled by user
 | 
				
			||||||
         * The system time of the sender of the packet at the time the packet was sent.
 | 
					
 | 
				
			||||||
         */
 | 
					    // payload: number (9 ... 12)
 | 
				
			||||||
        public time: number;
 | 
					    const PACKET_TYPE_NUMBER = 0;
 | 
				
			||||||
        /**
 | 
					    // payload: number (9 ... 12), name length (13), name (14 ... 26)
 | 
				
			||||||
         * The serial number of the sender of the packet or 0 if the sender did not sent their serial number.
 | 
					    const PACKET_TYPE_VALUE = 1;
 | 
				
			||||||
         */
 | 
					    // payload: string length (9), string (10 ... 28)
 | 
				
			||||||
        public serial: number;
 | 
					    const PACKET_TYPE_STRING = 2;
 | 
				
			||||||
        /**
 | 
					    // payload: buffer length (9), buffer (10 ... 28)
 | 
				
			||||||
         * The received signal strength indicator (RSSI) of the packet.
 | 
					    const PACKET_TYPE_BUFFER = 3;
 | 
				
			||||||
         */
 | 
					    // payload: number (9 ... 16)
 | 
				
			||||||
        public signal: number;
 | 
					    const PACKET_TYPE_DOUBLE = 4;
 | 
				
			||||||
    }
 | 
					    // payload: number (9 ... 16), name length (17), name (18 ... 26)
 | 
				
			||||||
 | 
					    const PACKET_TYPE_DOUBLE_VALUE = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let transmittingSerial: boolean;
 | 
				
			||||||
 | 
					    let initialized = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export let lastPacket: RadioPacket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function init() {
 | 
				
			||||||
 | 
					        if (initialized) return;
 | 
				
			||||||
 | 
					        initialized = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Registers code to run when the radio receives a packet. Also takes the
 | 
					 | 
				
			||||||
     * received packet from the radio queue.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/on-data-packet-received blockHandlerKey="radioreceived" deprecated=true
 | 
					 | 
				
			||||||
    //% mutate=objectdestructuring
 | 
					 | 
				
			||||||
    //% mutateText=Packet
 | 
					 | 
				
			||||||
    //% mutateDefaults="receivedNumber;receivedString:name,receivedNumber:value;receivedString"
 | 
					 | 
				
			||||||
    //% blockId=radio_on_packet block="on radio received" blockGap=8
 | 
					 | 
				
			||||||
    export function onDataPacketReceived(cb: (packet: Packet) => void) {
 | 
					 | 
				
			||||||
        onDataReceived(() => {
 | 
					        onDataReceived(() => {
 | 
				
			||||||
            receiveNumber();
 | 
					            lastPacket = RadioPacket.getPacket(readRawPacket());
 | 
				
			||||||
            const packet = new Packet();
 | 
					            lastPacket.signal = receivedSignalStrength();
 | 
				
			||||||
            packet.receivedNumber = receivedNumber();
 | 
					
 | 
				
			||||||
            packet.time = receivedTime();
 | 
					            switch (lastPacket.packetType) {
 | 
				
			||||||
            packet.serial = receivedSerial();
 | 
					                case PACKET_TYPE_NUMBER:
 | 
				
			||||||
            packet.receivedString = receivedString();
 | 
					                case PACKET_TYPE_DOUBLE:
 | 
				
			||||||
            packet.receivedBuffer = receivedBuffer();
 | 
					                    control.raiseEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_NUMBER);
 | 
				
			||||||
            packet.signal = receivedSignalStrength();
 | 
					                    break;
 | 
				
			||||||
            lastPacket = packet;
 | 
					                case PACKET_TYPE_VALUE:
 | 
				
			||||||
            cb(packet)
 | 
					                case PACKET_TYPE_DOUBLE_VALUE:
 | 
				
			||||||
        });
 | 
					                    control.raiseEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_VALUE);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case PACKET_TYPE_BUFFER:
 | 
				
			||||||
 | 
					                    control.raiseEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_BUFFER);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case PACKET_TYPE_STRING:
 | 
				
			||||||
 | 
					                    control.raiseEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_STRING);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Registers code to run when the radio receives a number.
 | 
					     * Registers code to run when the radio receives a number.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/on-received-number blockHandlerKey="radioreceived"
 | 
					    //% help=radio/on-received-number
 | 
				
			||||||
    //% blockId=radio_on_number_drag block="on radio received" blockGap=16
 | 
					    //% blockId=radio_on_number_drag block="on radio received" blockGap=16
 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
					    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
				
			||||||
    export function onReceivedNumber(cb: (receivedNumber: number) => void) {
 | 
					    export function onReceivedNumber(cb: (receivedNumber: number) => void) {
 | 
				
			||||||
        onDataReceived(() => {
 | 
					        init();
 | 
				
			||||||
            receiveNumber();
 | 
					        control.onEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_NUMBER, () => {
 | 
				
			||||||
            const packet = new Packet();
 | 
					            cb(lastPacket.numberPayload);
 | 
				
			||||||
            packet.time = receivedTime();
 | 
					 | 
				
			||||||
            packet.serial = receivedSerial();
 | 
					 | 
				
			||||||
            packet.signal = receivedSignalStrength();
 | 
					 | 
				
			||||||
            packet.receivedNumber = receivedNumber();
 | 
					 | 
				
			||||||
            lastPacket = packet;
 | 
					 | 
				
			||||||
            cb(packet.receivedNumber);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Registers code to run when the radio receives a key value pair.
 | 
					     * Registers code to run when the radio receives a key value pair.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/on-received-value blockHandlerKey="radioreceived"
 | 
					    //% help=radio/on-received-value
 | 
				
			||||||
    //% blockId=radio_on_value_drag block="on radio received" blockGap=16
 | 
					    //% blockId=radio_on_value_drag block="on radio received" blockGap=16
 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
					    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
				
			||||||
    export function onReceivedValue(cb: (name: string, value: number) => void) {
 | 
					    export function onReceivedValue(cb: (name: string, value: number) => void) {
 | 
				
			||||||
        onDataReceived(() => {
 | 
					        init();
 | 
				
			||||||
            receiveNumber();
 | 
					        control.onEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_VALUE, () => {
 | 
				
			||||||
            const packet = new Packet();
 | 
					            cb(lastPacket.stringPayload, lastPacket.numberPayload);
 | 
				
			||||||
            packet.time = receivedTime();
 | 
					 | 
				
			||||||
            packet.serial = receivedSerial();
 | 
					 | 
				
			||||||
            packet.signal = receivedSignalStrength();
 | 
					 | 
				
			||||||
            packet.receivedNumber = receivedNumber();
 | 
					 | 
				
			||||||
            packet.receivedString = receivedString();
 | 
					 | 
				
			||||||
            lastPacket = packet;
 | 
					 | 
				
			||||||
            cb(packet.receivedString, packet.receivedNumber)
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Registers code to run when the radio receives a string.
 | 
					     * Registers code to run when the radio receives a string.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/on-received-string blockHandlerKey="radioreceived"
 | 
					    //% help=radio/on-received-string
 | 
				
			||||||
    //% blockId=radio_on_string_drag block="on radio received" blockGap=16
 | 
					    //% blockId=radio_on_string_drag block="on radio received" blockGap=16
 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
					    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
				
			||||||
    export function onReceivedString(cb: (receivedString: string) => void) {
 | 
					    export function onReceivedString(cb: (receivedString: string) => void) {
 | 
				
			||||||
        onDataReceived(() => {
 | 
					        init();
 | 
				
			||||||
            receiveNumber();
 | 
					        control.onEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_STRING, () => {
 | 
				
			||||||
            const packet = new Packet();
 | 
					            cb(lastPacket.stringPayload);
 | 
				
			||||||
            packet.time = receivedTime();
 | 
					 | 
				
			||||||
            packet.serial = receivedSerial();
 | 
					 | 
				
			||||||
            packet.signal = receivedSignalStrength();
 | 
					 | 
				
			||||||
            packet.receivedString = receivedString();
 | 
					 | 
				
			||||||
            lastPacket = packet;
 | 
					 | 
				
			||||||
            cb(packet.receivedString);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Registers code to run when the radio receives a buffer.
 | 
					     * Registers code to run when the radio receives a buffer.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/on-received-buffer blockHandlerKey="radioreceived" blockHidden=1
 | 
					    //% help=radio/on-received-buffer blockHidden=1
 | 
				
			||||||
    //% blockId=radio_on_buffer_drag block="on radio received" blockGap=16
 | 
					    //% blockId=radio_on_buffer_drag block="on radio received" blockGap=16
 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
					    //% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
 | 
				
			||||||
    export function onReceivedBuffer(cb: (receivedBuffer: Buffer) => void) {
 | 
					    export function onReceivedBuffer(cb: (receivedBuffer: Buffer) => void) {
 | 
				
			||||||
        onDataReceived(() => {
 | 
					        init();
 | 
				
			||||||
            receiveNumber();
 | 
					        control.onEvent(DAL.MICROBIT_ID_RADIO, MAKECODE_RADIO_EVT_BUFFER, () => {
 | 
				
			||||||
            const packet = new Packet();
 | 
					            cb(lastPacket.bufferPayload);
 | 
				
			||||||
            packet.time = receivedTime();
 | 
					 | 
				
			||||||
            packet.serial = receivedSerial();
 | 
					 | 
				
			||||||
            packet.signal = receivedSignalStrength();
 | 
					 | 
				
			||||||
            packet.receivedBuffer = receivedBuffer();
 | 
					 | 
				
			||||||
            lastPacket = packet;
 | 
					 | 
				
			||||||
            cb(packet.receivedBuffer)
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Registers code to run when the radio receives a number. Deprecated, use
 | 
					 | 
				
			||||||
     * onReceivedNumber instead.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/on-received-number blockHandlerKey="radioreceived"
 | 
					 | 
				
			||||||
    //% blockId=radio_on_number block="on radio received" blockGap=16
 | 
					 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
					 | 
				
			||||||
    export function onReceivedNumberDeprecated(cb: (receivedNumber: number) => void) {
 | 
					 | 
				
			||||||
        onReceivedNumber(cb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Registers code to run when the radio receives a key value pair. Deprecated, use
 | 
					 | 
				
			||||||
     * onReceivedValue instead.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/on-received-value blockHandlerKey="radioreceived"
 | 
					 | 
				
			||||||
    //% blockId=radio_on_value block="on radio received" blockGap=16
 | 
					 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
					 | 
				
			||||||
    export function onReceivedValueDeprecated(cb: (name: string, value: number) => void) {
 | 
					 | 
				
			||||||
        onReceivedValue(cb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Registers code to run when the radio receives a string. Deprecated, use
 | 
					 | 
				
			||||||
     * onReceivedString instead.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/on-received-string blockHandlerKey="radioreceived"
 | 
					 | 
				
			||||||
    //% blockId=radio_on_string block="on radio received" blockGap=16
 | 
					 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
					 | 
				
			||||||
    export function onReceivedStringDeprecated(cb: (receivedString: string) => void) {
 | 
					 | 
				
			||||||
        onReceivedString(cb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Registers code to run when the radio receives a buffer. Deprecated, use
 | 
					 | 
				
			||||||
     * onReceivedBuffer instead.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/on-received-buffer blockHandlerKey="radioreceived" blockHidden=1
 | 
					 | 
				
			||||||
    //% blockId=radio_on_buffer block="on radio received" blockGap=16
 | 
					 | 
				
			||||||
    //% useLoc="radio.onDataPacketReceived" deprecated=1
 | 
					 | 
				
			||||||
    export function onReceivedBufferDeprecated(cb: (receivedBuffer: Buffer) => void) {
 | 
					 | 
				
			||||||
        onReceivedBuffer(cb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let lastPacket: Packet;
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns properties of the last radio packet received.
 | 
					     * Returns properties of the last radio packet received.
 | 
				
			||||||
     * @param type the type of property to retrieve from the last packet
 | 
					     * @param type the type of property to retrieve from the last packet
 | 
				
			||||||
@@ -219,4 +158,271 @@ namespace radio {
 | 
				
			|||||||
    export function _packetProperty(type: RadioPacketProperty): number {
 | 
					    export function _packetProperty(type: RadioPacketProperty): number {
 | 
				
			||||||
        return type;
 | 
					        return type;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					
 | 
				
			||||||
 | 
					    export class RadioPacket {
 | 
				
			||||||
 | 
					        public static getPacket(data: Buffer) {
 | 
				
			||||||
 | 
					            return new RadioPacket(data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static mkPacket(packetType: number) {
 | 
				
			||||||
 | 
					            const res = new RadioPacket();
 | 
				
			||||||
 | 
					            res.data[0] = packetType;
 | 
				
			||||||
 | 
					            return res;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private constructor(public readonly data?: Buffer) {
 | 
				
			||||||
 | 
					            if (!data) this.data = control.createBuffer(32);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public signal: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get packetType() {
 | 
				
			||||||
 | 
					            return this.data[0];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get time() {
 | 
				
			||||||
 | 
					            return this.data.getNumber(NumberFormat.Int32LE, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set time(val: number) {
 | 
				
			||||||
 | 
					            this.data.setNumber(NumberFormat.Int32LE, 1, val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get serial() {
 | 
				
			||||||
 | 
					            return this.data.getNumber(NumberFormat.Int32LE, 5);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set serial(val: number) {
 | 
				
			||||||
 | 
					            this.data.setNumber(NumberFormat.Int32LE, 5, val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get stringPayload() {
 | 
				
			||||||
 | 
					            const offset = getStringOffset(this.packetType) as number;
 | 
				
			||||||
 | 
					            return offset ? this.data.slice(offset + 1, this.data[offset]).toString() : undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set stringPayload(val: string) {
 | 
				
			||||||
 | 
					            const offset = getStringOffset(this.packetType) as number;
 | 
				
			||||||
 | 
					            if (offset) {
 | 
				
			||||||
 | 
					                const buf = control.createBufferFromUTF8(truncateString(val, getMaxStringLength(this.packetType)));
 | 
				
			||||||
 | 
					                this.data[offset] = buf.length;
 | 
				
			||||||
 | 
					                this.data.write(offset + 1, buf);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get numberPayload() {
 | 
				
			||||||
 | 
					            switch (this.packetType) {
 | 
				
			||||||
 | 
					                case PACKET_TYPE_NUMBER:
 | 
				
			||||||
 | 
					                case PACKET_TYPE_VALUE:
 | 
				
			||||||
 | 
					                    return this.data.getNumber(NumberFormat.Int32LE, PACKET_PREFIX_LENGTH);
 | 
				
			||||||
 | 
					                case PACKET_TYPE_DOUBLE:
 | 
				
			||||||
 | 
					                case PACKET_TYPE_DOUBLE_VALUE:
 | 
				
			||||||
 | 
					                    return this.data.getNumber(NumberFormat.Float64LE, PACKET_PREFIX_LENGTH);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set numberPayload(val: number) {
 | 
				
			||||||
 | 
					            switch (this.packetType) {
 | 
				
			||||||
 | 
					                case PACKET_TYPE_NUMBER:
 | 
				
			||||||
 | 
					                case PACKET_TYPE_VALUE:
 | 
				
			||||||
 | 
					                    this.data.setNumber(NumberFormat.Int32LE, PACKET_PREFIX_LENGTH, val);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case PACKET_TYPE_DOUBLE:
 | 
				
			||||||
 | 
					                case PACKET_TYPE_DOUBLE_VALUE:
 | 
				
			||||||
 | 
					                    this.data.setNumber(NumberFormat.Float64LE, PACKET_PREFIX_LENGTH, val);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get bufferPayload() {
 | 
				
			||||||
 | 
					            const len = this.data[PACKET_PREFIX_LENGTH];
 | 
				
			||||||
 | 
					            return this.data.slice(PACKET_PREFIX_LENGTH + 1, len);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set bufferPayload(b: Buffer) {
 | 
				
			||||||
 | 
					            const len = Math.min(b.length, MAX_PAYLOAD_LENGTH - 1);
 | 
				
			||||||
 | 
					            this.data[PACKET_PREFIX_LENGTH] = len;
 | 
				
			||||||
 | 
					            this.data.write(PACKET_PREFIX_LENGTH + 1, b.slice(0, len));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hasString() {
 | 
				
			||||||
 | 
					            return this.packetType === PACKET_TYPE_STRING ||
 | 
				
			||||||
 | 
					                this.packetType === PACKET_TYPE_VALUE ||
 | 
				
			||||||
 | 
					                this.packetType === PACKET_TYPE_DOUBLE_VALUE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hasNumber() {
 | 
				
			||||||
 | 
					            return this.packetType === PACKET_TYPE_NUMBER ||
 | 
				
			||||||
 | 
					                this.packetType === PACKET_TYPE_DOUBLE ||
 | 
				
			||||||
 | 
					                this.packetType === PACKET_TYPE_VALUE ||
 | 
				
			||||||
 | 
					                this.packetType === PACKET_TYPE_DOUBLE_VALUE;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Broadcasts a number over radio to any connected micro:bit in the group.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/send-number
 | 
				
			||||||
 | 
					    //% weight=60
 | 
				
			||||||
 | 
					    //% blockId=radio_datagram_send block="radio send number %value" blockGap=8
 | 
				
			||||||
 | 
					    export function sendNumber(value: number) {
 | 
				
			||||||
 | 
					        let packet: RadioPacket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (value === (value | 0)) {
 | 
				
			||||||
 | 
					            packet = RadioPacket.mkPacket(PACKET_TYPE_NUMBER);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        packet.numberPayload = value;
 | 
				
			||||||
 | 
					        sendPacket(packet);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Broadcasts a name / value pair along with the device serial number
 | 
				
			||||||
 | 
					    * and running time to any connected micro:bit in the group. The name can
 | 
				
			||||||
 | 
					    * include no more than 8 characters.
 | 
				
			||||||
 | 
					    * @param name the field name (max 8 characters), eg: "name"
 | 
				
			||||||
 | 
					    * @param value the numeric value
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    //% help=radio/send-value
 | 
				
			||||||
 | 
					    //% weight=59
 | 
				
			||||||
 | 
					    //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8
 | 
				
			||||||
 | 
					    export function sendValue(name: string, value: number) {
 | 
				
			||||||
 | 
					        let packet: RadioPacket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (value === (value | 0)) {
 | 
				
			||||||
 | 
					            packet = RadioPacket.mkPacket(PACKET_TYPE_VALUE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE_VALUE);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        packet.numberPayload = value;
 | 
				
			||||||
 | 
					        packet.stringPayload = name;
 | 
				
			||||||
 | 
					        sendPacket(packet);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Broadcasts a string along with the device serial number
 | 
				
			||||||
 | 
					     * and running time to any connected micro:bit in the group.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    //% help=radio/send-string
 | 
				
			||||||
 | 
					    //% weight=58
 | 
				
			||||||
 | 
					    //% blockId=radio_datagram_send_string block="radio send string %msg"
 | 
				
			||||||
 | 
					    //% msg.shadowOptions.toString=true
 | 
				
			||||||
 | 
					    export function sendString(value: string) {
 | 
				
			||||||
 | 
					        const packet = RadioPacket.mkPacket(PACKET_TYPE_STRING);
 | 
				
			||||||
 | 
					        packet.stringPayload = value;
 | 
				
			||||||
 | 
					        sendPacket(packet);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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
 | 
				
			||||||
 | 
					    export function sendBuffer(msg: Buffer) {
 | 
				
			||||||
 | 
					        const packet = RadioPacket.mkPacket(PACKET_TYPE_BUFFER);
 | 
				
			||||||
 | 
					        packet.bufferPayload = msg;
 | 
				
			||||||
 | 
					        sendPacket(packet);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Writes the last received packet to serial as JSON. This should be called
 | 
				
			||||||
 | 
					    * within an ``onDataPacketReceived`` callback.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    //% help=radio/write-received-packet-to-serial
 | 
				
			||||||
 | 
					    //% weight=3
 | 
				
			||||||
 | 
					    //% blockId=radio_write_packet_serial block="radio write received packet to serial"
 | 
				
			||||||
 | 
					    //% advanced=true
 | 
				
			||||||
 | 
					    export function writeReceivedPacketToSerial() {
 | 
				
			||||||
 | 
					        if (lastPacket) writeToSerial(lastPacket)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    * Set the radio to transmit the serial number in each message.
 | 
				
			||||||
 | 
					    * @param transmit value indicating if the serial number is transmitted, eg: true
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    //% help=radio/set-transmit-serial-number
 | 
				
			||||||
 | 
					    //% weight=8 blockGap=8
 | 
				
			||||||
 | 
					    //% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit"
 | 
				
			||||||
 | 
					    //% advanced=true
 | 
				
			||||||
 | 
					    export function setTransmitSerialNumber(transmit: boolean) {
 | 
				
			||||||
 | 
					        transmittingSerial = transmit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function writeToSerial(packet: RadioPacket) {
 | 
				
			||||||
 | 
					        serial.writeString("{");
 | 
				
			||||||
 | 
					        serial.writeString("\"t\":");
 | 
				
			||||||
 | 
					        serial.writeString("" + packet.time);
 | 
				
			||||||
 | 
					        serial.writeString(",\"s\":");
 | 
				
			||||||
 | 
					        serial.writeString("" + packet.serial);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (packet.hasString()) {
 | 
				
			||||||
 | 
					            serial.writeString(",\"n\":\"");
 | 
				
			||||||
 | 
					            serial.writeString(packet.stringPayload);
 | 
				
			||||||
 | 
					            serial.writeString("\"");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (packet.packetType == PACKET_TYPE_BUFFER) {
 | 
				
			||||||
 | 
					            serial.writeString(",\"b\":\"");
 | 
				
			||||||
 | 
					            // TODO: proper base64 encoding
 | 
				
			||||||
 | 
					            serial.writeString(packet.bufferPayload.toString());
 | 
				
			||||||
 | 
					            serial.writeString("\"");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (packet.hasNumber()) {
 | 
				
			||||||
 | 
					            serial.writeString(",\"v\":");
 | 
				
			||||||
 | 
					            serial.writeString("" + packet.numberPayload);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        serial.writeString("}\r\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function sendPacket(packet: RadioPacket) {
 | 
				
			||||||
 | 
					        packet.time = input.runningTime();
 | 
				
			||||||
 | 
					        packet.serial = transmittingSerial ? control.deviceSerialNumber() : 0;
 | 
				
			||||||
 | 
					        radio.sendRawPacket(packet.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function truncateString(str: string, bytes: number) {
 | 
				
			||||||
 | 
					        str = str.substr(0, bytes);
 | 
				
			||||||
 | 
					        let buff = control.createBufferFromUTF8(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (buff.length > bytes) {
 | 
				
			||||||
 | 
					            str = str.substr(0, str.length - 1);
 | 
				
			||||||
 | 
					            buff = control.createBufferFromUTF8(str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function getStringOffset(packetType: number) {
 | 
				
			||||||
 | 
					        switch (packetType) {
 | 
				
			||||||
 | 
					            case PACKET_TYPE_STRING:
 | 
				
			||||||
 | 
					                return PACKET_PREFIX_LENGTH;
 | 
				
			||||||
 | 
					            case PACKET_TYPE_VALUE:
 | 
				
			||||||
 | 
					                return VALUE_PACKET_NAME_LEN_OFFSET;
 | 
				
			||||||
 | 
					            case PACKET_TYPE_DOUBLE_VALUE:
 | 
				
			||||||
 | 
					                return DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function getMaxStringLength(packetType: number) {
 | 
				
			||||||
 | 
					        switch (packetType) {
 | 
				
			||||||
 | 
					            case PACKET_TYPE_STRING:
 | 
				
			||||||
 | 
					                return MAX_PAYLOAD_LENGTH - 2;
 | 
				
			||||||
 | 
					            case PACKET_TYPE_VALUE:
 | 
				
			||||||
 | 
					            case PACKET_TYPE_DOUBLE_VALUE:
 | 
				
			||||||
 | 
					                return MAX_FIELD_DOUBLE_NAME_LENGTH;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								libs/radio/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										130
									
								
								libs/radio/shims.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ declare namespace radio {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Sends an event over radio to neigboring devices
 | 
					     * Sends an event over radio to neigboring devices
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id" 
 | 
					    //% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id"
 | 
				
			||||||
    //% blockExternalInputs=1
 | 
					    //% blockExternalInputs=1
 | 
				
			||||||
    //% advanced=true
 | 
					    //% advanced=true
 | 
				
			||||||
    //% weight=1
 | 
					    //% weight=1
 | 
				
			||||||
@@ -16,72 +16,16 @@ declare namespace radio {
 | 
				
			|||||||
    function raiseEvent(src: int32, value: int32): void;
 | 
					    function raiseEvent(src: int32, value: int32): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Broadcasts a number over radio to any connected micro:bit in the group.
 | 
					     * Takes the next packet from the radio queue and returns its contents in a Buffer
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/send-number
 | 
					    //% help=radio/received-packet shim=radio::readRawPacket
 | 
				
			||||||
    //% weight=60
 | 
					    function readRawPacket(): Buffer;
 | 
				
			||||||
    //% blockId=radio_datagram_send block="radio send number %value" blockGap=8 shim=radio::sendNumber
 | 
					 | 
				
			||||||
    function sendNumber(value: number): void;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Broadcasts a name / value pair along with the device serial number
 | 
					     * Sends a raw packet through the radio
 | 
				
			||||||
     * and running time to any connected micro:bit in the group.
 | 
					 | 
				
			||||||
     * @param name the field name (max 12 characters), eg: "name"
 | 
					 | 
				
			||||||
     * @param value the numeric value
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    //% help=radio/send-value
 | 
					    //% advanced=true shim=radio::sendRawPacket
 | 
				
			||||||
    //% weight=59
 | 
					    function sendRawPacket(msg: Buffer): void;
 | 
				
			||||||
    //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8 shim=radio::sendValue
 | 
					 | 
				
			||||||
    function sendValue(name: string, value: number): void;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Broadcasts a string along with the device serial number
 | 
					 | 
				
			||||||
     * and running time to any connected micro:bit in the group.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/send-string
 | 
					 | 
				
			||||||
    //% weight=58
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_send_string block="radio send string %msg"
 | 
					 | 
				
			||||||
    //% msg.shadowOptions.toString=true 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.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/write-value-to-serial
 | 
					 | 
				
			||||||
    //% weight=3
 | 
					 | 
				
			||||||
    //% blockId=radio_write_value_serial block="radio write value to serial"
 | 
					 | 
				
			||||||
    //% deprecated=true shim=radio::writeValueToSerial
 | 
					 | 
				
			||||||
    function writeValueToSerial(): void;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Writes the last received packet to serial as JSON. This should be called
 | 
					 | 
				
			||||||
     * within an ``onDataPacketReceived`` callback.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/write-received-packet-to-serial
 | 
					 | 
				
			||||||
    //% weight=3
 | 
					 | 
				
			||||||
    //% blockId=radio_write_packet_serial block="radio write received packet to serial"
 | 
					 | 
				
			||||||
    //% advanced=true shim=radio::writeReceivedPacketToSerial
 | 
					 | 
				
			||||||
    function writeReceivedPacketToSerial(): void;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Reads the next packet from the radio queue and returns the packet's number
 | 
					 | 
				
			||||||
     * payload or 0 if the packet did not contain a number.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/receive-number
 | 
					 | 
				
			||||||
    //% weight=46
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_receive block="radio receive number" blockGap=8
 | 
					 | 
				
			||||||
    //% deprecated=true shim=radio::receiveNumber
 | 
					 | 
				
			||||||
    function receiveNumber(): number;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Registers code to run when a packet is received over radio.
 | 
					     * Registers code to run when a packet is received over radio.
 | 
				
			||||||
@@ -92,16 +36,6 @@ declare namespace radio {
 | 
				
			|||||||
    //% deprecated=true shim=radio::onDataReceived
 | 
					    //% deprecated=true shim=radio::onDataReceived
 | 
				
			||||||
    function onDataReceived(body: () => void): void;
 | 
					    function onDataReceived(body: () => void): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Reads the next packet from the radio queue and returns the packet's string
 | 
					 | 
				
			||||||
     * payload or the empty string if the packet did not contain a string.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8
 | 
					 | 
				
			||||||
    //% weight=44
 | 
					 | 
				
			||||||
    //% help=radio/receive-string
 | 
					 | 
				
			||||||
    //% deprecated=true shim=radio::receiveString
 | 
					 | 
				
			||||||
    function receiveString(): string;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the received signal strength indicator (RSSI) from the last packet taken
 | 
					     * Gets the received signal strength indicator (RSSI) from the last packet taken
 | 
				
			||||||
     * from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.
 | 
					     * from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.
 | 
				
			||||||
@@ -133,56 +67,6 @@ declare namespace radio {
 | 
				
			|||||||
    //% power.min=0 power.max=7
 | 
					    //% power.min=0 power.max=7
 | 
				
			||||||
    //% advanced=true shim=radio::setTransmitPower
 | 
					    //% advanced=true shim=radio::setTransmitPower
 | 
				
			||||||
    function setTransmitPower(power: int32): void;
 | 
					    function setTransmitPower(power: int32): void;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Set the radio to transmit the serial number in each message.
 | 
					 | 
				
			||||||
     * @param transmit value indicating if the serial number is transmitted, eg: true
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/set-transmit-serial-number
 | 
					 | 
				
			||||||
    //% weight=8 blockGap=8
 | 
					 | 
				
			||||||
    //% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit"
 | 
					 | 
				
			||||||
    //% advanced=true shim=radio::setTransmitSerialNumber
 | 
					 | 
				
			||||||
    function setTransmitSerialNumber(transmit: boolean): void;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns the number payload from the last packet taken from the radio queue
 | 
					 | 
				
			||||||
     * (via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not
 | 
					 | 
				
			||||||
     * contain a number.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/received-number shim=radio::receivedNumber
 | 
					 | 
				
			||||||
    function receivedNumber(): number;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns the serial number of the sender micro:bit from the last packet taken
 | 
					 | 
				
			||||||
     * from the radio queue (via ``receiveNumber``, ``receiveString``, etc) or 0 if
 | 
					 | 
				
			||||||
     * that packet did not send a serial number.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/received-serial shim=radio::receivedSerial
 | 
					 | 
				
			||||||
    function receivedSerial(): uint32;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns the string 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-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``,
 | 
					 | 
				
			||||||
     * ``receiveString``, etc).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    //% help=radio/received-time shim=radio::receivedTime
 | 
					 | 
				
			||||||
    function receivedTime(): uint32;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Auto-generated. Do not edit. Really.
 | 
					// Auto-generated. Do not edit. Really.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										349
									
								
								libs/radio/test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								libs/radio/test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,349 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Tests for the radio. Press A on mbit 1 and B on mbit 2 to run the tests.
 | 
				
			||||||
 | 
					 * Sends random ints, doubles, strings, and buffers and checks them on
 | 
				
			||||||
 | 
					 * the other side
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FastRandom {
 | 
				
			||||||
 | 
					    private lfsr: number;
 | 
				
			||||||
 | 
					    public seed: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(seed?: number) {
 | 
				
			||||||
 | 
					        if (seed === undefined) seed = Math.randomRange(0x0001, 0xFFFF);
 | 
				
			||||||
 | 
					        this.seed = seed;
 | 
				
			||||||
 | 
					        this.lfsr = seed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    next(): number {
 | 
				
			||||||
 | 
					        return this.lfsr = (this.lfsr >> 1) ^ ((-(this.lfsr & 1)) & 0xb400);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    randomRange(min: number, max: number): number {
 | 
				
			||||||
 | 
					        return min + (max > min ? this.next() % (max - min + 1) : 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reset() {
 | 
				
			||||||
 | 
					        this.lfsr = this.seed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum TestStage {
 | 
				
			||||||
 | 
					    Integer,
 | 
				
			||||||
 | 
					    String,
 | 
				
			||||||
 | 
					    Double,
 | 
				
			||||||
 | 
					    IntValue,
 | 
				
			||||||
 | 
					    DblValue,
 | 
				
			||||||
 | 
					    Buffer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TEST_COUNT = 30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					radio.setGroup(78)
 | 
				
			||||||
 | 
					const rand = new FastRandom(1234);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let stage = TestStage.Integer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function initSender() {
 | 
				
			||||||
 | 
					    let lastReceived: number;
 | 
				
			||||||
 | 
					    let lastString: string;
 | 
				
			||||||
 | 
					    let testIndex = 0;
 | 
				
			||||||
 | 
					    let lastBuf: Buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let lastAck = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rand.reset();
 | 
				
			||||||
 | 
					    basic.clearScreen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Send loop
 | 
				
			||||||
 | 
					    control.inBackground(function () {
 | 
				
			||||||
 | 
					        while (true) {
 | 
				
			||||||
 | 
					            for (let i = 0; i < TEST_COUNT; i++) {
 | 
				
			||||||
 | 
					                toggle(testIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (stage === TestStage.Integer) {
 | 
				
			||||||
 | 
					                    lastReceived = getNextInt();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (stage === TestStage.Double) {
 | 
				
			||||||
 | 
					                    lastReceived = getNextDouble();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (stage === TestStage.IntValue) {
 | 
				
			||||||
 | 
					                    lastString = getNextName();
 | 
				
			||||||
 | 
					                    console.log(truncateString(lastString, 8))
 | 
				
			||||||
 | 
					                    lastReceived = getNextInt();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (stage === TestStage.DblValue) {
 | 
				
			||||||
 | 
					                    lastString = getNextName();
 | 
				
			||||||
 | 
					                    lastReceived = getNextDouble();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (stage === TestStage.String) {
 | 
				
			||||||
 | 
					                    lastString = getNextString();
 | 
				
			||||||
 | 
					                    console.log(truncateString(lastString, 19))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (stage === TestStage.Buffer) {
 | 
				
			||||||
 | 
					                    lastBuf = getNextBuffer();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                while (lastAck !== testIndex) {
 | 
				
			||||||
 | 
					                    if (stage === TestStage.Integer || stage === TestStage.Double) {
 | 
				
			||||||
 | 
					                        radio.sendNumber(lastReceived)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (stage === TestStage.IntValue || stage === TestStage.DblValue) {
 | 
				
			||||||
 | 
					                        radio.sendValue(lastString, lastReceived)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (stage === TestStage.String) {
 | 
				
			||||||
 | 
					                        radio.sendString(lastString);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (stage === TestStage.Buffer) {
 | 
				
			||||||
 | 
					                        radio.sendBuffer(lastBuf);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    basic.pause(10);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                testIndex++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            stage++;
 | 
				
			||||||
 | 
					            if (stage > TestStage.Buffer) {
 | 
				
			||||||
 | 
					                basic.showIcon(IconNames.Yes);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    radio.onReceivedNumber(function (receivedNumber: number) {
 | 
				
			||||||
 | 
					        if (receivedNumber > lastAck) {
 | 
				
			||||||
 | 
					            lastAck = receivedNumber;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let lastReceived: number;
 | 
				
			||||||
 | 
					let lastString: string;
 | 
				
			||||||
 | 
					let testIndex = -1;
 | 
				
			||||||
 | 
					let running = true;
 | 
				
			||||||
 | 
					let lastBuf: Buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let lastPacket = new radio.Packet();
 | 
				
			||||||
 | 
					let currentPacket = new radio.Packet();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function truncateString(str: string, bytes: number) {
 | 
				
			||||||
 | 
					    str = str.substr(0, bytes);
 | 
				
			||||||
 | 
					    let buff = control.createBufferFromUTF8(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (buff.length > bytes) {
 | 
				
			||||||
 | 
					        str = str.substr(0, str.length - 1);
 | 
				
			||||||
 | 
					        buff = control.createBufferFromUTF8(str);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return str;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function initReceiver() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rand.reset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    basic.clearScreen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    radio.onDataReceived(function () {
 | 
				
			||||||
 | 
					        radio.receiveNumber();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        currentPacket.receivedNumber = radio.receivedNumber();
 | 
				
			||||||
 | 
					        currentPacket.receivedString = radio.receivedString();
 | 
				
			||||||
 | 
					        currentPacket.receivedBuffer = radio.receivedBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (currentPacket.receivedNumber === lastPacket.receivedNumber &&
 | 
				
			||||||
 | 
					            currentPacket.receivedString === lastPacket.receivedString &&
 | 
				
			||||||
 | 
					            checkBufferEqual(currentPacket.receivedBuffer, lastPacket.receivedBuffer)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lastPacket.receivedNumber = currentPacket.receivedNumber
 | 
				
			||||||
 | 
					        lastPacket.receivedString = currentPacket.receivedString
 | 
				
			||||||
 | 
					        lastPacket.receivedBuffer = currentPacket.receivedBuffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (stage) {
 | 
				
			||||||
 | 
					            case TestStage.Integer:
 | 
				
			||||||
 | 
					                verifyInt(radio.receivedNumber());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case TestStage.Double:
 | 
				
			||||||
 | 
					                verifyDouble(radio.receivedNumber());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case TestStage.IntValue:
 | 
				
			||||||
 | 
					                verifyIntValue(radio.receivedString(), radio.receivedNumber());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case TestStage.DblValue:
 | 
				
			||||||
 | 
					                verifyDblValue(radio.receivedString(), radio.receivedNumber());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case TestStage.String:
 | 
				
			||||||
 | 
					                verifyString(radio.receivedString());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case TestStage.Buffer:
 | 
				
			||||||
 | 
					                verifyBuffer(radio.receivedBuffer());
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    control.inBackground(function () {
 | 
				
			||||||
 | 
					        while (running) {
 | 
				
			||||||
 | 
					            radio.sendNumber(testIndex);
 | 
				
			||||||
 | 
					            basic.pause(10)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function nextTest() {
 | 
				
			||||||
 | 
					    testIndex++;
 | 
				
			||||||
 | 
					    toggle(testIndex);
 | 
				
			||||||
 | 
					    console.log(`test ${testIndex}`)
 | 
				
			||||||
 | 
					    if (((testIndex + 1) % TEST_COUNT) === 0) {
 | 
				
			||||||
 | 
					        stage++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (stage > TestStage.Buffer) {
 | 
				
			||||||
 | 
					            basic.showIcon(IconNames.Yes)
 | 
				
			||||||
 | 
					            running = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function verifyInt(int: number) {
 | 
				
			||||||
 | 
					    if (int === lastReceived) return;
 | 
				
			||||||
 | 
					    lastReceived = int;
 | 
				
			||||||
 | 
					    if (lastReceived != getNextInt()) fail();
 | 
				
			||||||
 | 
					    nextTest()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function verifyDouble(dbl: number) {
 | 
				
			||||||
 | 
					    if (dbl === lastReceived) return;
 | 
				
			||||||
 | 
					    lastReceived = dbl;
 | 
				
			||||||
 | 
					    if (lastReceived != getNextDouble()) fail();
 | 
				
			||||||
 | 
					    nextTest()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function verifyIntValue(name: string, val: number) {
 | 
				
			||||||
 | 
					    if (val === lastReceived) return;
 | 
				
			||||||
 | 
					    lastReceived = val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (name != truncateString(getNextName(), 8) || lastReceived != getNextInt()) fail();
 | 
				
			||||||
 | 
					    nextTest()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function verifyDblValue(name: string, val: number) {
 | 
				
			||||||
 | 
					    if (val === lastReceived) return;
 | 
				
			||||||
 | 
					    lastReceived = val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (name != truncateString(getNextName(), 8) || lastReceived != getNextDouble()) fail();
 | 
				
			||||||
 | 
					    nextTest()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function verifyString(str: string) {
 | 
				
			||||||
 | 
					    if (!str || str === lastString) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lastString = str;
 | 
				
			||||||
 | 
					    let next = truncateString(getNextString(), 19);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (lastString !== next) {
 | 
				
			||||||
 | 
					        console.log(`got ${control.createBufferFromUTF8(lastString).toHex()} expected ${control.createBufferFromUTF8(next).toHex()}`)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nextTest()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function verifyBuffer(buf: Buffer) {
 | 
				
			||||||
 | 
					    if (checkBufferEqual(lastBuf, buf)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lastBuf = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!checkBufferEqual(lastBuf, getNextBuffer())) {
 | 
				
			||||||
 | 
					        fail();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    nextTest()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fail() {
 | 
				
			||||||
 | 
					    control.panic(testIndex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let _lastInt: number;
 | 
				
			||||||
 | 
					let _lastDbl: number;
 | 
				
			||||||
 | 
					let _lastStr: string;
 | 
				
			||||||
 | 
					let _lastBuf: Buffer;
 | 
				
			||||||
 | 
					let _lastNam: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getNextInt(): number {
 | 
				
			||||||
 | 
					    let res = rand.next();
 | 
				
			||||||
 | 
					    if (!res || res === _lastInt) return getNextInt();
 | 
				
			||||||
 | 
					    _lastInt = res;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getNextDouble(): number {
 | 
				
			||||||
 | 
					    let res = rand.next() / rand.next();
 | 
				
			||||||
 | 
					    if (res === _lastDbl) return getNextDouble();
 | 
				
			||||||
 | 
					    _lastDbl = res;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getNextString(): string {
 | 
				
			||||||
 | 
					    let len = rand.randomRange(1, 19);
 | 
				
			||||||
 | 
					    let res = "";
 | 
				
			||||||
 | 
					    for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        res += String.fromCharCode(rand.next() & 0xbfff);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (res === _lastStr) return getNextString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _lastStr = res;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getNextName(): string {
 | 
				
			||||||
 | 
					    let len = rand.randomRange(1, 8);
 | 
				
			||||||
 | 
					    let res = "";
 | 
				
			||||||
 | 
					    for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        res += String.fromCharCode(rand.next() & 0xbfff);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (res === _lastNam) return getNextName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _lastNam = res;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getNextBuffer(): Buffer {
 | 
				
			||||||
 | 
					    let len = rand.randomRange(0, 8);
 | 
				
			||||||
 | 
					    let res = control.createBuffer(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
					        res[i] = rand.next() & 0xff;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (checkBufferEqual(_lastBuf, res)) return getNextBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _lastBuf = res;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function checkBufferEqual(a: Buffer, b: Buffer) {
 | 
				
			||||||
 | 
					    if (a === b) return true;
 | 
				
			||||||
 | 
					    if ((!a && b) || (a && !b)) return false;
 | 
				
			||||||
 | 
					    if (a.length != b.length) return false;
 | 
				
			||||||
 | 
					    for (let i = 0; i < a.length; i++) {
 | 
				
			||||||
 | 
					        if (a[i] !== b[i]) return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					input.onButtonPressed(Button.A, function () {
 | 
				
			||||||
 | 
					    basic.showString("S");
 | 
				
			||||||
 | 
					    initSender();
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					input.onButtonPressed(Button.B, function () {
 | 
				
			||||||
 | 
					    basic.showString("R");
 | 
				
			||||||
 | 
					    initReceiver();
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function toggle(index: number) {
 | 
				
			||||||
 | 
					    const x = index % 5;
 | 
				
			||||||
 | 
					    const y = Math.idiv(index, 5) % 5;
 | 
				
			||||||
 | 
					    led.toggle(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -96,13 +96,6 @@ namespace pxsim {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace pxsim.radio {
 | 
					namespace pxsim.radio {
 | 
				
			||||||
    enum PacketPayloadType {
 | 
					 | 
				
			||||||
        NUMBER = 0,
 | 
					 | 
				
			||||||
        VALUE = 1,
 | 
					 | 
				
			||||||
        STRING = 2,
 | 
					 | 
				
			||||||
        BUFFER = 3
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function raiseEvent(id: number, eventid: number): void {
 | 
					    export function raiseEvent(id: number, eventid: number): void {
 | 
				
			||||||
        board().radioState.raiseEvent(id, eventid);
 | 
					        board().radioState.raiseEvent(id, eventid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -115,70 +108,17 @@ namespace pxsim.radio {
 | 
				
			|||||||
        board().radioState.setTransmitPower(power);
 | 
					        board().radioState.setTransmitPower(power);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    export function setTransmitSerialNumber(transmit: boolean): void {
 | 
					    export function sendRawPacket(buf: RefBuffer) {
 | 
				
			||||||
        board().radioState.setTransmitSerialNumber(transmit);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function sendNumber(value: number): void {
 | 
					 | 
				
			||||||
        board().radioState.datagram.send({
 | 
					        board().radioState.datagram.send({
 | 
				
			||||||
            type: PacketPayloadType.NUMBER,
 | 
					            type: 0,
 | 
				
			||||||
            groupId: board().radioState.groupId,
 | 
					            groupId: board().radioState.groupId,
 | 
				
			||||||
            numberData: value,
 | 
					            bufferData: buf.data
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    export function sendString(msg: string): void {
 | 
					    export function readRawPacket() {
 | 
				
			||||||
        if (msg === undefined) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        msg = msg.substr(0, 19);
 | 
					 | 
				
			||||||
        board().radioState.datagram.send({
 | 
					 | 
				
			||||||
            type: PacketPayloadType.STRING,
 | 
					 | 
				
			||||||
            groupId: board().radioState.groupId,
 | 
					 | 
				
			||||||
            stringData: msg,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function sendBuffer(buf: RefBuffer): void {
 | 
					 | 
				
			||||||
        if (!buf) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const data = buf.data.slice(0, 18);
 | 
					 | 
				
			||||||
        board().radioState.datagram.send({
 | 
					 | 
				
			||||||
            type: PacketPayloadType.STRING,
 | 
					 | 
				
			||||||
            groupId: board().radioState.groupId,
 | 
					 | 
				
			||||||
            bufferData: data
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function writeValueToSerial(): void {
 | 
					 | 
				
			||||||
        const b = board();
 | 
					 | 
				
			||||||
        writePacketToSerial(b, b.radioState.datagram.recv())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function writeReceivedPacketToSerial(): void {
 | 
					 | 
				
			||||||
        const b = board();
 | 
					 | 
				
			||||||
        writePacketToSerial(b, b.radioState.datagram.lastReceived);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function sendValue(name: string, value: number) {
 | 
					 | 
				
			||||||
        name = name.substr(0, 8);
 | 
					 | 
				
			||||||
        const msg: number[] = [];
 | 
					 | 
				
			||||||
        msg.push()
 | 
					 | 
				
			||||||
        board().radioState.datagram.send({
 | 
					 | 
				
			||||||
            type: PacketPayloadType.VALUE,
 | 
					 | 
				
			||||||
            groupId: board().radioState.groupId,
 | 
					 | 
				
			||||||
            stringData: name,
 | 
					 | 
				
			||||||
            numberData: value
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receiveNumber(): number {
 | 
					 | 
				
			||||||
        const packet = board().radioState.datagram.recv();
 | 
					        const packet = board().radioState.datagram.recv();
 | 
				
			||||||
        return receivedNumber();
 | 
					        return new RefBuffer(packet.payload.bufferData)
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receiveString(): string {
 | 
					 | 
				
			||||||
        const packet = board().radioState.datagram.recv();
 | 
					 | 
				
			||||||
        return receivedString();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    export function receivedSignalStrength(): number {
 | 
					    export function receivedSignalStrength(): number {
 | 
				
			||||||
@@ -187,50 +127,6 @@ namespace pxsim.radio {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    export function onDataReceived(handler: RefAction): void {
 | 
					    export function onDataReceived(handler: RefAction): void {
 | 
				
			||||||
        pxtcore.registerWithDal(DAL.MICROBIT_ID_RADIO, DAL.MICROBIT_RADIO_EVT_DATAGRAM, handler);
 | 
					        pxtcore.registerWithDal(DAL.MICROBIT_ID_RADIO, DAL.MICROBIT_RADIO_EVT_DATAGRAM, handler);
 | 
				
			||||||
        radio.receiveNumber();
 | 
					        readRawPacket();
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receivedNumber(): number {
 | 
					 | 
				
			||||||
        return board().radioState.datagram.lastReceived.payload.numberData || 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receivedSerial(): number {
 | 
					 | 
				
			||||||
        return board().radioState.datagram.lastReceived.serial;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receivedString(): string {
 | 
					 | 
				
			||||||
        return initString(board().radioState.datagram.lastReceived.payload.stringData || "");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receivedBuffer(): RefBuffer {
 | 
					 | 
				
			||||||
        return new RefBuffer(board().radioState.datagram.lastReceived.payload.bufferData || new Uint8Array(0))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    export function receivedTime(): number {
 | 
					 | 
				
			||||||
        return board().radioState.datagram.lastReceived.time;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function writePacketToSerial(b: DalBoard, p: PacketBuffer) {
 | 
					 | 
				
			||||||
        switch (p.payload.type) {
 | 
					 | 
				
			||||||
            case PacketPayloadType.NUMBER:
 | 
					 | 
				
			||||||
                b.writeSerial(`{"t":${p.time},"s":${p.serial},"v":${p.payload.numberData}}\r\n`)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case PacketPayloadType.VALUE:
 | 
					 | 
				
			||||||
                b.writeSerial(`{"t":${p.time},"s":${p.serial},"n":"${p.payload.stringData}","v":${p.payload.numberData}}\r\n`)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case PacketPayloadType.STRING:
 | 
					 | 
				
			||||||
                b.writeSerial(`{"t":${p.time},"s":${p.serial},"n":"${p.payload.stringData}"}\r\n`)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            // TODO: (microbit master)
 | 
					 | 
				
			||||||
            // case PacketPayloadType.BUFFER:
 | 
					 | 
				
			||||||
            //     const buf = new Uint8Array(p.payload.bufferData.buffer);
 | 
					 | 
				
			||||||
            //     let res = "";
 | 
					 | 
				
			||||||
            //     for (let i = 0; i < buf.length; ++i)
 | 
					 | 
				
			||||||
            //         res += String.fromCharCode(buf[i]);
 | 
					 | 
				
			||||||
            //     b.writeSerial(`{"t":${p.time},"s":${p.serial},"b":"${res}"}\r\n`)
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                // unknown type
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user