2.1.28, initiation update to PXT v5.28.24 (#54)
This commit is contained in:
committed by
Peli de Halleux
parent
38a964516e
commit
5c114a0c57
@ -1,23 +0,0 @@
|
||||
{
|
||||
"radio": "Daten mithilfe von Funk-Paketen übertragen",
|
||||
"radio.onDataPacketReceived": "Registriert Funktionen, die ausgeführt werden, wenn das Radio ein Datenpaket empfängt. Entnimmt das empfangene Paket aus der Warteschlange des Radios.",
|
||||
"radio.onDataReceived": "Registriert Code der ausgeführt wird, wenn ein Paket über Funk empfangen wird.",
|
||||
"radio.receiveNumber": "Liest das nächste Paket aus der Funk-Warteschlange und gibt die Paketnummer oder 0 aus, wenn das Paket keine Nummer enthält.",
|
||||
"radio.receiveString": "Liest das nächste Paket aus der Funk-Warteschlange und gibt die enthaltene Zeichenfolge oder die leere Zeichenfolge aus, wenn das Paket keine Zeichenfolge enthält.",
|
||||
"radio.receivedNumber": "Extrahiert eine Zahl aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios (via ``Zahl empfangen``, ``Zeichenkette empfangen``, etc) entnommen wurde oder eine 0, wenn das Paket keine Zahl enthält.",
|
||||
"radio.receivedSerial": "Extrahiert die Seriennummer des Calliope mini Senders aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios entnommen wurde oder eine 0, wenn der Absender keine Seriennummer gesendet hat.",
|
||||
"radio.receivedSignalStrength": "Ruft den empfangenen Signalstärkeindikator (RSSI) aus dem letzten Paket aus der Funk-Warteschlange aus (via ``receiveNumber``, ``receiveString``, etc). Wird im Simulator nicht unterstützt.\nnamespace=radio",
|
||||
"radio.receivedString": "Extrahiert die Zeichenkette aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios (via ``Zahl empfangen``, ``Zeichenkette empfangen``, etc) entnommen wurde oder eine leere Zeichenkette, wenn das Paket keine Zeichenkette enthält.",
|
||||
"radio.receivedTime": "Extrahiert die Systemzeit des Absenders aus dem Inhalt des letzten Datenpakets, welches aus der Warteschlange des Radios (via ``Zahl empfangen``, ``Zeichenkette empfangen``, etc) entnommen wurde.",
|
||||
"radio.sendNumber": "Überträgt eine Nummer über Funk an jeden angeschlossenen mini in der Gruppe.",
|
||||
"radio.sendString": "Überträgt eine Zeichenfolge über Funk mit Seriennummer des Geräts und Laufzeit an jeden angeschlossenen mini in der Gruppe.",
|
||||
"radio.sendValue": "Sendet ein Name / Wert-Paar zusammen mit der Seriennummer des Geräts und die Laufzeit auf alle angeschlossenen minis in der Gruppe.",
|
||||
"radio.sendValue|param|value": "der numerische Wert",
|
||||
"radio.setGroup": "Setzt die Gruppen-ID für Funkverbindungen. Ein mini kann nur ein Gruppen-ID hören.\nDie Gruppen-ID zwischen liegt zwischen 0 und 255, z.B. 1",
|
||||
"radio.setTransmitPower": "Ändere die Ausgabeleistung des Senders auf den angegebenen Wert.",
|
||||
"radio.setTransmitPower|param|power": "ein Wert im Bereich 0.. 7, wo 0 die niedrigste Leistung und 7 ist ist die höchste. z.B. 7",
|
||||
"radio.setTransmitSerialNumber": "Stelle den Dunk so ein, dass die Seriennummer in jeder Nachricht übertragen wird.",
|
||||
"radio.setTransmitSerialNumber|param|transmit": "Wert, der anzeigt, ob die Seriennummer übertragen wird, z.B. wahr",
|
||||
"radio.writeReceivedPacketToSerial": "Schreibt das letzte empfangene Paket als JSON auf Seriell. Sollte in einem ´´onDataPacketReceived``-Callback aufgerufen werden.",
|
||||
"radio.writeValueToSerial": "Liest das nächste Paket aus der Funk-Warteschlange und schreibt dieses als JSON auf Seriell."
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"radio.onDataPacketReceived|block": "wenn Datenpaket empfangen",
|
||||
"radio.onDataReceived|block": "Funk auf empfangenen Daten",
|
||||
"radio.receiveNumber|block": "empfange Nummer über Funk",
|
||||
"radio.receiveString|block": "empfange Zeichenfolge über Funk",
|
||||
"radio.receivedSignalStrength|block": "über Funk empfangene Signalstärke",
|
||||
"radio.sendNumber|block": "sende Nummer %value über Funk",
|
||||
"radio.sendString|block": "sende Zeichenfolge %msg über Funk",
|
||||
"radio.sendValue|block": "schicke |Wert %name|= %value über Funk",
|
||||
"radio.setGroup|block": "setze Gruppe %ID über Funk",
|
||||
"radio.setTransmitPower|block": "setze Übertragungsstärke %power über Funk",
|
||||
"radio.setTransmitSerialNumber|block": "setze Übertragungsseriennummer %transmit über Funk",
|
||||
"radio.writeReceivedPacketToSerial|block": "schreibe das über Funk übertragene Paket auf Seriell",
|
||||
"radio.writeValueToSerial|block": "schreibe Wert über Funk auf Seriell",
|
||||
"radio|block": "Funk",
|
||||
"{id:category}Radio": "Funk"
|
||||
}
|
@ -1,25 +1,46 @@
|
||||
{
|
||||
"radio": "Communicate data using radio packets",
|
||||
"radio.Packet.receivedBuffer": "The buffer payload if a buffer was sent in this packet\nor the empty buffer",
|
||||
"radio.Packet.receivedNumber": "The number payload if a number was sent in this packet (via ``sendNumber()`` or ``sendValue()``)\nor 0 if this packet did not contain a number.",
|
||||
"radio.Packet.receivedString": "The string payload if a string was sent in this packet (via ``sendString()`` or ``sendValue()``)\nor the empty string if this packet did not contain a string.",
|
||||
"radio.Packet.serial": "The serial number of the sender of the packet or 0 if the sender did not sent their serial number.",
|
||||
"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.onDataPacketReceived": "Registers code to run when the radio receives a packet. Also takes the\nreceived packet from the radio queue.",
|
||||
"radio._packetProperty": "Gets a packet property.",
|
||||
"radio._packetProperty|param|type": "the packet property type, eg: PacketProperty.time",
|
||||
"radio.onDataPacketReceived": "Deprecated. Use onDataReceived() instead\nRegisters code to run when the radio receives a packet. Also takes the\nreceived packet from the radio queue.",
|
||||
"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.onReceivedBufferDeprecated": "Registers code to run when the radio receives a buffer. Deprecated, use\nonReceivedBuffer instead.",
|
||||
"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.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.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.raiseEvent": "Sends an event over radio to neigboring devices",
|
||||
"radio.readRawPacket": "Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer",
|
||||
"radio.receiveNumber": "Reads the next packet from the radio queue and returns the packet's number\npayload or 0 if the packet did not contain a number.",
|
||||
"radio.receiveString": "Reads the next packet from the radio queue and returns the packet's string\npayload or the empty string if the packet did not contain a string.",
|
||||
"radio.receivedBuffer": "Returns the buffer payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.",
|
||||
"radio.receivedNumber": "Returns the number payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or 0 if that packet did not\ncontain a number.",
|
||||
"radio.receivedPacket": "Returns properties of the last radio packet received.",
|
||||
"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.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.",
|
||||
"radio.receivedString": "Returns the string payload from the last packet taken from the radio queue\n(via ``receiveNumber``, ``receiveString``, etc) or the empty string if that\npacket did not contain a string.",
|
||||
"radio.receivedTime": "Returns the system time of the sender micro:bit at the moment when it sent the\nlast packet taken from the radio queue (via ``receiveNumber``,\n``receiveString``, etc).",
|
||||
"radio.sendBuffer": "Broadcasts a buffer (up to 19 bytes long) along with the device serial number\nand running time to any connected micro:bit in the group.",
|
||||
"radio.sendNumber": "Broadcasts a number over radio to any connected micro:bit in the group.",
|
||||
"radio.sendRawPacket": "Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet)",
|
||||
"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|param|name": "the field name (max 12 characters), eg: \"name\"",
|
||||
"radio.sendValue|param|value": "the numberic value",
|
||||
"radio.setGroup": "Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.\n@ param id the group id between ``0`` and ``255``, 1 eg",
|
||||
"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 8 characters), eg: \"name\"",
|
||||
"radio.sendValue|param|value": "the numeric value",
|
||||
"radio.setFrequencyBand": "Change the transmission and reception band of the radio to the given channel",
|
||||
"radio.setFrequencyBand|param|band": "a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz.",
|
||||
"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.setTransmitPower": "Change the output power level of the transmitter to the given value.",
|
||||
"radio.setTransmitPower|param|power": "a value in the range 0..7, where 0 is the lowest power and 7 is the highest. eg: 7",
|
||||
"radio.setTransmitSerialNumber": "Set the radio to transmit the serial number in each message.",
|
||||
|
@ -1,12 +1,27 @@
|
||||
{
|
||||
"RadioPacketProperty.SerialNumber|block": "serial number",
|
||||
"RadioPacketProperty.SignalStrength|block": "signal strength",
|
||||
"RadioPacketProperty.Time|block": "time",
|
||||
"radio._packetProperty|block": "%note",
|
||||
"radio.onDataPacketReceived|block": "on radio received",
|
||||
"radio.onDataReceived|block": "radio on data received",
|
||||
"radio.onReceivedBufferDeprecated|block": "on radio received",
|
||||
"radio.onReceivedBuffer|block": "on radio received",
|
||||
"radio.onReceivedNumberDeprecated|block": "on radio received",
|
||||
"radio.onReceivedNumber|block": "on radio received",
|
||||
"radio.onReceivedStringDeprecated|block": "on radio received",
|
||||
"radio.onReceivedString|block": "on radio received",
|
||||
"radio.onReceivedValueDeprecated|block": "on radio received",
|
||||
"radio.onReceivedValue|block": "on radio received",
|
||||
"radio.raiseEvent|block": "radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id",
|
||||
"radio.receiveNumber|block": "radio receive number",
|
||||
"radio.receiveString|block": "radio receive string",
|
||||
"radio.receivedPacket|block": "received packet %type=radio_packet_property",
|
||||
"radio.receivedSignalStrength|block": "radio received signal strength",
|
||||
"radio.sendNumber|block": "radio send number %value",
|
||||
"radio.sendString|block": "radio send string %msg",
|
||||
"radio.sendValue|block": "radio send|value %name|= %value",
|
||||
"radio.setFrequencyBand|block": "radio set frequency band %band",
|
||||
"radio.setGroup|block": "radio set group %ID",
|
||||
"radio.setTransmitPower|block": "radio set transmit power %power",
|
||||
"radio.setTransmitSerialNumber|block": "radio set transmit serial number %transmit",
|
||||
|
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();
|
||||
}
|
||||
}
|
@ -7,9 +7,9 @@
|
||||
"enums.d.ts",
|
||||
"radio.cpp",
|
||||
"radio.ts",
|
||||
"_locales/de/radio-jsdoc-strings.json",
|
||||
"_locales/de/radio-strings.json"
|
||||
"deprecated.ts"
|
||||
],
|
||||
"icon": "./static/packages/radio/icon.png",
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core"
|
||||
|
@ -2,44 +2,10 @@
|
||||
|
||||
using namespace pxt;
|
||||
|
||||
#define MAX_FIELD_NAME_LENGTH 12
|
||||
#define MAX_PAYLOAD_LENGTH 20
|
||||
#define PACKET_PREFIX_LENGTH 9
|
||||
#define VALUE_PACKET_NAME_LEN_OFFSET 13
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
//% color=270 weight=34
|
||||
//% color=#E3008C weight=96 icon="\uf012"
|
||||
namespace radio {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Radio
|
||||
// -------------------------------------------------------------------------
|
||||
bool radioEnabled = false;
|
||||
bool transmitSerialNumber = false;
|
||||
|
||||
PacketBuffer packet;
|
||||
|
||||
uint8_t type;
|
||||
uint32_t time;
|
||||
uint32_t serial;
|
||||
int value;
|
||||
StringData* msg;
|
||||
|
||||
int radioEnable() {
|
||||
int r = uBit.radio.enable();
|
||||
@ -49,224 +15,56 @@ namespace radio {
|
||||
}
|
||||
if (!radioEnabled) {
|
||||
uBit.radio.setGroup(pxt::programHash());
|
||||
uBit.radio.setTransmitPower(6); // start with high power by default
|
||||
radioEnabled = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void broadcastMessage(int message) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
uBit.radio.event.eventReceived(MicroBitEvent(MES_BROADCAST_GENERAL_ID, message, CREATE_ONLY));
|
||||
}
|
||||
|
||||
void onBroadcastMessageReceived(int message, Action f) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
registerWithDal(MES_BROADCAST_GENERAL_ID, message, f);
|
||||
}
|
||||
|
||||
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, StringData* data, uint8_t maxLength) {
|
||||
ManagedString s(data);
|
||||
uint8_t len = min(maxLength, s.length());
|
||||
|
||||
// One byte for length of the string
|
||||
buf[0] = len;
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(buf + 1, s.toCharArray(), len);
|
||||
}
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
StringData* getStringValue(uint8_t* buf, uint8_t maxLength) {
|
||||
// First byte is the string length
|
||||
uint8_t len = min(maxLength, buf[0]);
|
||||
|
||||
if (len) {
|
||||
char name[maxLength + 1];
|
||||
memcpy(name, buf + 1, len);
|
||||
name[len] = 0;
|
||||
return ManagedString(name).leakData();
|
||||
}
|
||||
return ManagedString().leakData();
|
||||
}
|
||||
|
||||
void writePacketAsJSON(uint8_t tp, int v, int s, int t, StringData* m) {
|
||||
// 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) {
|
||||
uBit.serial.send(",\"n\":\"");
|
||||
uBit.serial.send(m);
|
||||
uBit.serial.send("\"");
|
||||
}
|
||||
if (tp == PACKET_TYPE_NUMBER || tp == PACKET_TYPE_VALUE) {
|
||||
uBit.serial.send(",\"v\":");
|
||||
uBit.serial.send(v);
|
||||
}
|
||||
uBit.serial.send("}\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a packet from the micro:bit radio queue.
|
||||
* @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) {
|
||||
PacketBuffer p = uBit.radio.datagram.recv();
|
||||
|
||||
uint8_t* buf = p.getBytes();
|
||||
uint8_t tp;
|
||||
int t;
|
||||
int s;
|
||||
int v;
|
||||
StringData* m;
|
||||
|
||||
|
||||
memcpy(&tp, buf, 1);
|
||||
memcpy(&t, buf + 1, 4);
|
||||
memcpy(&s, buf + 5, 4);
|
||||
|
||||
if (tp == PACKET_TYPE_STRING) {
|
||||
v = 0;
|
||||
m = getStringValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1);
|
||||
}
|
||||
else {
|
||||
memcpy(&v, buf + 9, 4);
|
||||
if (tp == PACKET_TYPE_VALUE) {
|
||||
m = getStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_NAME_LENGTH);
|
||||
}
|
||||
else {
|
||||
m = ManagedString().leakData();
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeToSerial) {
|
||||
// Refresh global packet
|
||||
packet = p;
|
||||
type = tp;
|
||||
time = t;
|
||||
serial = s;
|
||||
value = v;
|
||||
msg = m;
|
||||
}
|
||||
else {
|
||||
writePacketAsJSON(tp, v, s, t, m);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
void sendNumber(int value) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
uint8_t length = PACKET_PREFIX_LENGTH + sizeof(uint32_t);
|
||||
uint8_t buf[length];
|
||||
memset(buf, 0, length);
|
||||
|
||||
setPacketPrefix(buf, PACKET_TYPE_NUMBER);
|
||||
memcpy(buf + PACKET_PREFIX_LENGTH, &value, 4);
|
||||
|
||||
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.
|
||||
* @param name the field name (max 12 characters), eg: "name"
|
||||
* @param value the numberic value
|
||||
* Sends an event over radio to neigboring devices
|
||||
*/
|
||||
//% help=radio/send-value
|
||||
//% weight=59
|
||||
//% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8
|
||||
void sendValue(StringData* name, int value) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
|
||||
ManagedString n(name);
|
||||
uint8_t buf[32];
|
||||
memset(buf, 0, 32);
|
||||
|
||||
setPacketPrefix(buf, PACKET_TYPE_VALUE);
|
||||
memcpy(buf + PACKET_PREFIX_LENGTH, &value, 4);
|
||||
|
||||
int stringLen = copyStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_NAME_LENGTH);
|
||||
|
||||
uBit.radio.datagram.send(buf, 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"
|
||||
void sendString(StringData* msg) {
|
||||
if (radioEnable() != MICROBIT_OK) 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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"
|
||||
//% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id"
|
||||
//% blockExternalInputs=1
|
||||
//% advanced=true
|
||||
void writeReceivedPacketToSerial() {
|
||||
//% weight=1
|
||||
//% help=radio/raise-event
|
||||
void raiseEvent(int src, int value) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
writePacketAsJSON(type, value, (int) serial, (int) time, msg);
|
||||
|
||||
uBit.radio.event.eventReceived(MicroBitEvent(src, value, CREATE_ONLY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer
|
||||
*/
|
||||
//% help=radio/receive-number
|
||||
//% weight=46
|
||||
//% blockId=radio_datagram_receive block="radio receive number" blockGap=8
|
||||
//% deprecated=true
|
||||
int receiveNumber()
|
||||
{
|
||||
if (radioEnable() != MICROBIT_OK) return 0;
|
||||
receivePacket(false);
|
||||
return value;
|
||||
//%
|
||||
Buffer readRawPacket() {
|
||||
if (radioEnable() != MICROBIT_OK) return mkBuffer(NULL, 0);
|
||||
|
||||
PacketBuffer p = uBit.radio.datagram.recv();
|
||||
if (p == PacketBuffer::EmptyPacket)
|
||||
return mkBuffer(NULL, 0);
|
||||
|
||||
int rssi = p.getRSSI();
|
||||
uint8_t buf[MICROBIT_RADIO_MAX_PACKET_SIZE + sizeof(int)]; // packet length + rssi
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, p.getBytes(), p.length()); // data
|
||||
memcpy(buf + MICROBIT_RADIO_MAX_PACKET_SIZE, &rssi, sizeof(int)); // RSSi - assumes Int32LE layout
|
||||
return mkBuffer(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet)
|
||||
*/
|
||||
//% async
|
||||
void sendRawPacket(Buffer msg) {
|
||||
if (radioEnable() != MICROBIT_OK || NULL == msg) return;
|
||||
|
||||
// don't send RSSI data; and make sure no buffer underflow
|
||||
int len = msg->length - sizeof(int);
|
||||
if (len > 0)
|
||||
uBit.radio.datagram.send(msg->data, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,49 +76,22 @@ namespace radio {
|
||||
//% deprecated=true
|
||||
void onDataReceived(Action body) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
|
||||
registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body);
|
||||
// make sure the receive buffer has a free spot
|
||||
receiveNumber();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
StringData* receiveString() {
|
||||
if (radioEnable() != MICROBIT_OK) return ManagedString().leakData();
|
||||
receivePacket(false);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the received signal strength indicator (RSSI) from the last packet taken
|
||||
* from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.
|
||||
* namespace=radio
|
||||
*/
|
||||
//% help=radio/received-signal-strength
|
||||
//% weight=40
|
||||
//% blockId=radio_datagram_rssi block="radio received signal strength"
|
||||
//% deprecated=true
|
||||
int receivedSignalStrength() {
|
||||
if (radioEnable() != MICROBIT_OK) return 0;
|
||||
return packet.getRSSI();
|
||||
uBit.radio.datagram.recv(); // wake up read code
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.
|
||||
* @ param id the group id between ``0`` and ``255``, 1 eg
|
||||
* @param id the group id between ``0`` and ``255``, eg: 1
|
||||
*/
|
||||
//% help=radio/set-group
|
||||
//% weight=10 blockGap=8 advanced=true
|
||||
//% weight=100
|
||||
//% blockId=radio_set_group block="radio set group %ID"
|
||||
//% id.min=0 id.max=255
|
||||
void setGroup(int id) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
|
||||
uBit.radio.setGroup(id);
|
||||
}
|
||||
|
||||
@ -331,66 +102,25 @@ namespace radio {
|
||||
//% help=radio/set-transmit-power
|
||||
//% weight=9 blockGap=8
|
||||
//% blockId=radio_set_transmit_power block="radio set transmit power %power"
|
||||
//% power.min=0 power.max=7
|
||||
//% advanced=true
|
||||
void setTransmitPower(int power) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
|
||||
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
|
||||
* Change the transmission and reception band of the radio to the given channel
|
||||
* @param band a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz.
|
||||
**/
|
||||
//% help=radio/set-frequency-band
|
||||
//% weight=8 blockGap=8
|
||||
//% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit"
|
||||
//% blockId=radio_set_frequency_band block="radio set frequency band %band"
|
||||
//% band.min=0 band.max=83
|
||||
//% advanced=true
|
||||
void setTransmitSerialNumber(bool transmit) {
|
||||
void setFrequencyBand(int band) {
|
||||
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
|
||||
int receivedNumber() {
|
||||
if (radioEnable() != MICROBIT_OK) return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
StringData* receivedString() {
|
||||
if (radioEnable() != MICROBIT_OK) return ManagedString().leakData();
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
uBit.radio.setFrequencyBand(band);
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +1,444 @@
|
||||
|
||||
enum RadioPacketProperty {
|
||||
//% blockIdentity=radio._packetProperty
|
||||
//% block="signal strength"
|
||||
SignalStrength = 2,
|
||||
//% blockIdentity=radio._packetProperty
|
||||
//% block="time"
|
||||
Time = 0,
|
||||
//% block="serial number"
|
||||
//% blockIdentity=radio._packetProperty
|
||||
SerialNumber = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Communicate data using radio packets
|
||||
*/
|
||||
//% color=#E3008C weight=34 icon="\uf012"
|
||||
//% color=#E3008C weight=96 icon="\uf012"
|
||||
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 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;
|
||||
|
||||
const MAX_FIELD_DOUBLE_NAME_LENGTH = 8;
|
||||
const MAX_PAYLOAD_LENGTH = 20;
|
||||
const PACKET_PREFIX_LENGTH = 9;
|
||||
const VALUE_PACKET_NAME_LEN_OFFSET = 13;
|
||||
const 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)
|
||||
const PACKET_TYPE_NUMBER = 0;
|
||||
// payload: number (9 ... 12), name length (13), name (14 ... 26)
|
||||
const PACKET_TYPE_VALUE = 1;
|
||||
// payload: string length (9), string (10 ... 28)
|
||||
const PACKET_TYPE_STRING = 2;
|
||||
// payload: buffer length (9), buffer (10 ... 28)
|
||||
const PACKET_TYPE_BUFFER = 3;
|
||||
// payload: number (9 ... 16)
|
||||
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;
|
||||
let onReceivedNumberHandler: (receivedNumber: number) => void;
|
||||
let onReceivedValueHandler: (name: string, value: number) => void;
|
||||
let onReceivedStringHandler: (receivedString: string) => void;
|
||||
let onReceivedBufferHandler: (receivedBuffer: Buffer) => void;
|
||||
|
||||
function init() {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
onDataReceived(handleDataReceived);
|
||||
}
|
||||
|
||||
function handleDataReceived() {
|
||||
let buffer: Buffer = readRawPacket();
|
||||
while (buffer && buffer.length) {
|
||||
lastPacket = RadioPacket.getPacket(buffer);
|
||||
switch (lastPacket.packetType) {
|
||||
case PACKET_TYPE_NUMBER:
|
||||
case PACKET_TYPE_DOUBLE:
|
||||
if (onReceivedNumberHandler)
|
||||
onReceivedNumberHandler(lastPacket.numberPayload);
|
||||
break;
|
||||
case PACKET_TYPE_VALUE:
|
||||
case PACKET_TYPE_DOUBLE_VALUE:
|
||||
if (onReceivedValueHandler)
|
||||
onReceivedValueHandler(lastPacket.stringPayload, lastPacket.numberPayload);
|
||||
break;
|
||||
case PACKET_TYPE_BUFFER:
|
||||
if (onReceivedBufferHandler)
|
||||
onReceivedBufferHandler(lastPacket.bufferPayload);
|
||||
break;
|
||||
case PACKET_TYPE_STRING:
|
||||
if (onReceivedStringHandler)
|
||||
onReceivedStringHandler(lastPacket.stringPayload);
|
||||
break;
|
||||
}
|
||||
|
||||
// read next packet if any
|
||||
buffer = readRawPacket();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the radio receives a packet. Also takes the
|
||||
* received packet from the radio queue.
|
||||
* Registers code to run when the radio receives a number.
|
||||
*/
|
||||
//% help=radio/on-data-packet-received
|
||||
//% 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.signal = receivedSignalStrength();
|
||||
cb(packet)
|
||||
});
|
||||
//% help=radio/on-received-number
|
||||
//% blockId=radio_on_number_drag block="on radio received" blockGap=16
|
||||
//% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
|
||||
export function onReceivedNumber(cb: (receivedNumber: number) => void) {
|
||||
init();
|
||||
onReceivedNumberHandler = cb;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the radio receives a key value pair.
|
||||
*/
|
||||
//% help=radio/on-received-value
|
||||
//% blockId=radio_on_value_drag block="on radio received" blockGap=16
|
||||
//% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
|
||||
export function onReceivedValue(cb: (name: string, value: number) => void) {
|
||||
init();
|
||||
onReceivedValueHandler = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the radio receives a string.
|
||||
*/
|
||||
//% help=radio/on-received-string
|
||||
//% blockId=radio_on_string_drag block="on radio received" blockGap=16
|
||||
//% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
|
||||
export function onReceivedString(cb: (receivedString: string) => void) {
|
||||
init();
|
||||
onReceivedStringHandler = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the radio receives a buffer.
|
||||
*/
|
||||
//% help=radio/on-received-buffer blockHidden=1
|
||||
//% blockId=radio_on_buffer_drag block="on radio received" blockGap=16
|
||||
//% useLoc="radio.onDataPacketReceived" draggableParameters=reporter
|
||||
export function onReceivedBuffer(cb: (receivedBuffer: Buffer) => void) {
|
||||
init();
|
||||
onReceivedBufferHandler = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns properties of the last radio packet received.
|
||||
* @param type the type of property to retrieve from the last packet
|
||||
*/
|
||||
//% help=radio/received-packet
|
||||
//% weight=11 blockGap=8
|
||||
//% blockId=radio_received_packet block="received packet %type=radio_packet_property" blockGap=16
|
||||
export function receivedPacket(type: number) {
|
||||
if (lastPacket) {
|
||||
switch (type) {
|
||||
case RadioPacketProperty.Time: return lastPacket.time;
|
||||
case RadioPacketProperty.SerialNumber: return lastPacket.serial;
|
||||
case RadioPacketProperty.SignalStrength: return lastPacket.signal;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a packet property.
|
||||
* @param type the packet property type, eg: PacketProperty.time
|
||||
*/
|
||||
//% blockId=radio_packet_property block="%note"
|
||||
//% shim=TD_ID blockHidden=1
|
||||
export function _packetProperty(type: RadioPacketProperty): number {
|
||||
return type;
|
||||
}
|
||||
|
||||
export class RadioPacket {
|
||||
public static getPacket(data: Buffer) {
|
||||
// last 4 bytes is RSSi
|
||||
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(DAL.MICROBIT_RADIO_MAX_PACKET_SIZE + 4);
|
||||
}
|
||||
|
||||
get signal() {
|
||||
return this.data.getNumber(NumberFormat.Int32LE, this.data.length - 4);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the received signal strength indicator (RSSI) from the last packet taken
|
||||
* from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.
|
||||
*/
|
||||
//% help=radio/received-signal-strength
|
||||
//% weight=40
|
||||
//% blockId=radio_datagram_rssi block="radio received signal strength"
|
||||
//% deprecated=true blockHidden=true
|
||||
export function receivedSignalStrength(): number {
|
||||
return lastPacket ? lastPacket.signal : 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
144
libs/radio/shims.d.ts
vendored
144
libs/radio/shims.d.ts
vendored
@ -2,66 +2,30 @@
|
||||
|
||||
|
||||
|
||||
//% color=270 weight=34
|
||||
//% color=#E3008C weight=96 icon="\uf012"
|
||||
declare namespace radio {
|
||||
|
||||
/**
|
||||
* Broadcasts a number over radio to any connected micro:bit in the group.
|
||||
* Sends an event over radio to neigboring devices
|
||||
*/
|
||||
//% help=radio/send-number
|
||||
//% weight=60
|
||||
//% blockId=radio_datagram_send block="radio send number %value" blockGap=8 shim=radio::sendNumber
|
||||
function sendNumber(value: number): void;
|
||||
//% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id"
|
||||
//% blockExternalInputs=1
|
||||
//% advanced=true
|
||||
//% weight=1
|
||||
//% help=radio/raise-event shim=radio::raiseEvent
|
||||
function raiseEvent(src: int32, value: int32): void;
|
||||
|
||||
/**
|
||||
* Broadcasts a name / value pair along with the device serial number
|
||||
* and running time to any connected micro:bit in the group.
|
||||
* @param name the field name (max 12 characters), eg: "name"
|
||||
* @param value the numberic value
|
||||
* Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer
|
||||
*/
|
||||
//% help=radio/send-value
|
||||
//% weight=59
|
||||
//% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8 shim=radio::sendValue
|
||||
function sendValue(name: string, value: number): void;
|
||||
//% shim=radio::readRawPacket
|
||||
function readRawPacket(): Buffer;
|
||||
|
||||
/**
|
||||
* Broadcasts a string along with the device serial number
|
||||
* and running time to any connected micro:bit in the group.
|
||||
* Internal use only. Sends a raw packet through the radio (assumes RSSI appened to packet)
|
||||
*/
|
||||
//% help=radio/send-string
|
||||
//% weight=58
|
||||
//% blockId=radio_datagram_send_string block="radio send string %msg" shim=radio::sendString
|
||||
function sendString(msg: string): 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;
|
||||
//% async shim=radio::sendRawPacket
|
||||
function sendRawPacket(msg: Buffer): void;
|
||||
|
||||
/**
|
||||
* Registers code to run when a packet is received over radio.
|
||||
@ -72,35 +36,15 @@ declare namespace radio {
|
||||
//% deprecated=true shim=radio::onDataReceived
|
||||
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
|
||||
* from the radio queue (via ``receiveNumber``, ``receiveString``, etc). Not supported in simulator.
|
||||
* namespace=radio
|
||||
*/
|
||||
//% help=radio/received-signal-strength
|
||||
//% weight=40
|
||||
//% blockId=radio_datagram_rssi block="radio received signal strength"
|
||||
//% deprecated=true shim=radio::receivedSignalStrength
|
||||
function receivedSignalStrength(): number;
|
||||
|
||||
/**
|
||||
* Sets the group id for radio communications. A micro:bit can only listen to one group ID at any time.
|
||||
* @ param id the group id between ``0`` and ``255``, 1 eg
|
||||
* @param id the group id between ``0`` and ``255``, eg: 1
|
||||
*/
|
||||
//% help=radio/set-group
|
||||
//% weight=10 blockGap=8 advanced=true
|
||||
//% blockId=radio_set_group block="radio set group %ID" shim=radio::setGroup
|
||||
function setGroup(id: number): void;
|
||||
//% weight=100
|
||||
//% blockId=radio_set_group block="radio set group %ID"
|
||||
//% id.min=0 id.max=255 shim=radio::setGroup
|
||||
function setGroup(id: int32): void;
|
||||
|
||||
/**
|
||||
* Change the output power level of the transmitter to the given value.
|
||||
@ -109,50 +53,20 @@ declare namespace radio {
|
||||
//% help=radio/set-transmit-power
|
||||
//% weight=9 blockGap=8
|
||||
//% blockId=radio_set_transmit_power block="radio set transmit power %power"
|
||||
//% power.min=0 power.max=7
|
||||
//% advanced=true shim=radio::setTransmitPower
|
||||
function setTransmitPower(power: number): 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
|
||||
* Change the transmission and reception band of the radio to the given channel
|
||||
* @param band a frequency band in the range 0 - 83. Each step is 1MHz wide, based at 2400MHz.
|
||||
**/
|
||||
//% help=radio/set-frequency-band
|
||||
//% 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(): number;
|
||||
|
||||
/**
|
||||
* 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 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(): number;
|
||||
//% blockId=radio_set_frequency_band block="radio set frequency band %band"
|
||||
//% band.min=0 band.max=83
|
||||
//% advanced=true shim=radio::setFrequencyBand
|
||||
function setFrequencyBand(band: int32): void;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
Reference in New Issue
Block a user