fetch pxt-microbit v2.2.30 (#102)
* undo buttonEvent * fetch microbit v2.2.30 Co-authored-by: Amerlander <gitkraken@juriwolf.de>
This commit is contained in:
@ -1,4 +0,0 @@
|
||||
# radio
|
||||
|
||||
The radio library.
|
||||
|
@ -9,7 +9,7 @@
|
||||
"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.onDataReceived": "Used internally by the library.",
|
||||
"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.",
|
||||
|
@ -1,19 +1,5 @@
|
||||
{
|
||||
"name": "radio",
|
||||
"description": "The radio services",
|
||||
"files": [
|
||||
"README.md",
|
||||
"shims.d.ts",
|
||||
"enums.d.ts",
|
||||
"radio.cpp",
|
||||
"radio.ts",
|
||||
"deprecated.ts"
|
||||
],
|
||||
"icon": "./static/packages/radio/icon.png",
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core"
|
||||
},
|
||||
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/radio",
|
||||
"yotta": {
|
||||
"config": {
|
||||
"microbit-dal": {
|
||||
@ -22,6 +8,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"installedVersion": "rlfgis"
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
#include "pxt.h"
|
||||
|
||||
using namespace pxt;
|
||||
|
||||
//% color=#E3008C weight=96 icon="\uf012"
|
||||
namespace radio {
|
||||
|
||||
bool radioEnabled = false;
|
||||
|
||||
int radioEnable() {
|
||||
int r = uBit.radio.enable();
|
||||
if (r != MICROBIT_OK) {
|
||||
uBit.panic(43);
|
||||
return r;
|
||||
}
|
||||
if (!radioEnabled) {
|
||||
uBit.radio.setGroup(pxt::programHash());
|
||||
uBit.radio.setTransmitPower(6); // start with high power by default
|
||||
radioEnabled = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an event over radio to neigboring devices
|
||||
*/
|
||||
//% blockId=radioRaiseEvent block="radio raise event|from source %src=control_event_source_id|with value %value=control_event_value_id"
|
||||
//% blockExternalInputs=1
|
||||
//% advanced=true
|
||||
//% weight=1
|
||||
//% help=radio/raise-event
|
||||
void raiseEvent(int src, int value) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
|
||||
uBit.radio.event.eventReceived(MicroBitEvent(src, value, CREATE_ONLY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal use only. Takes the next packet from the radio queue and returns its contents + RSSI in a Buffer
|
||||
*/
|
||||
//%
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when a packet is received over radio.
|
||||
*/
|
||||
//% help=radio/on-data-received
|
||||
//% weight=50
|
||||
//% blockId=radio_datagram_received_event block="radio on data received" blockGap=8
|
||||
//% deprecated=true
|
||||
void onDataReceived(Action body) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
|
||||
registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body);
|
||||
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``, eg: 1
|
||||
*/
|
||||
//% help=radio/set-group
|
||||
//% 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the output power level of the transmitter to the given value.
|
||||
* @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. eg: 7
|
||||
*/
|
||||
//% 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_frequency_band block="radio set frequency band %band"
|
||||
//% band.min=0 band.max=83
|
||||
//% advanced=true
|
||||
void setFrequencyBand(int band) {
|
||||
if (radioEnable() != MICROBIT_OK) return;
|
||||
uBit.radio.setFrequencyBand(band);
|
||||
}
|
||||
}
|
@ -1,444 +0,0 @@
|
||||
|
||||
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=96 icon="\uf012"
|
||||
namespace radio {
|
||||
|
||||
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 number.
|
||||
*/
|
||||
//% 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;
|
||||
}
|
||||
}
|
||||
}
|
6
libs/radio/shims.d.ts
vendored
6
libs/radio/shims.d.ts
vendored
@ -28,12 +28,12 @@ declare namespace radio {
|
||||
function sendRawPacket(msg: Buffer): void;
|
||||
|
||||
/**
|
||||
* Registers code to run when a packet is received over radio.
|
||||
* Used internally by the library.
|
||||
*/
|
||||
//% help=radio/on-data-received
|
||||
//% weight=50
|
||||
//% weight=0
|
||||
//% blockId=radio_datagram_received_event block="radio on data received" blockGap=8
|
||||
//% deprecated=true shim=radio::onDataReceived
|
||||
//% deprecated=true blockHidden=1 shim=radio::onDataReceived
|
||||
function onDataReceived(body: () => void): void;
|
||||
|
||||
/**
|
||||
|
@ -97,19 +97,6 @@ namespace radio {
|
||||
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
|
||||
@ -185,4 +172,67 @@ namespace radio {
|
||||
lastPacket = RadioPacket.getPacket(readRawPacket());
|
||||
return receivedString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 deprecated=true
|
||||
export function writeReceivedPacketToSerial() {
|
||||
if (lastPacket) writeToSerial(lastPacket)
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
@ -1,349 +0,0 @@
|
||||
/**
|
||||
* 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