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:
parent
19641abe92
commit
61aae94d8b
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
128
libs/radio/shims.d.ts
vendored
128
libs/radio/shims.d.ts
vendored
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user