From 93a22ae17fcdcb166d11d716fdc6e3eff3ebba9b Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Mon, 29 Oct 2018 10:42:12 -0700 Subject: [PATCH] radio double support (#1540) * support for doubles in radio * fix typos * more docs * more support * fix build * handle serial * fix length * fixing buffer allocation * use same notation * using decrRC --- docs/reference/radio/packet.md | 39 ++++++++++ libs/radio/radio.cpp | 129 ++++++++++++++++++++++++--------- libs/radio/shims.d.ts | 8 +- 3 files changed, 136 insertions(+), 40 deletions(-) diff --git a/docs/reference/radio/packet.md b/docs/reference/radio/packet.md index 7f842d76..2c129161 100644 --- a/docs/reference/radio/packet.md +++ b/docs/reference/radio/packet.md @@ -10,6 +10,45 @@ A packet that was received by the radio. * `serial` - The serial number of the @boardname@ that sent this packet or `0` if the @boardname@ did not include its serial number. * `signal` - How strong the radio signal is. The exact range of values varies, but it goes approximately from `-128` dB (weak) to `-42` dB (strong). +## Packet layout + +This section documents the data layout of the packet if you need to interpret the data outside of MakeCode. + + Packet byte layout + | 0 | 1 ... 4 | 5 ... 8 | 9 ... 28 + ---------------------------------------------------------------- + | packet type | system time | serial number | payload + +* Serial number defaults to 0 unless enabled by user +* system time is milli-seconds since started, it will wrap around after a month or so + +### Packet types + +* PACKET_TYPE_NUMBER 0 + + payload: number (9 ... 12) + + +* PACKET_TYPE_VALUE 1 + + payload: number (9 ... 12), name length (13), name (14 ... 26) + +* PACKET_TYPE_STRING 2 + + payload: string length (9), string (10 ... 28) + +* PACKET_TYPE_BUFFER 3 + + payload: buffer length (9), buffer (10 ... 28) + +* PACKET_TYPE_DOUBLE 4 + + payload: number (9 ... 16) + +* PACKET_TYPE_DOUBLE_VALUE 5 + + payload: number (9 ... 16), name length (17), name (18 ... 26) + ## See also [on data packet received](/reference/radio/on-data-packet-received), diff --git a/libs/radio/radio.cpp b/libs/radio/radio.cpp index 239eb998..8ed2b28c 100644 --- a/libs/radio/radio.cpp +++ b/libs/radio/radio.cpp @@ -3,9 +3,11 @@ using namespace pxt; #define MAX_FIELD_NAME_LENGTH 12 +#define MAX_FIELD_DOUBLE_NAME_LENGTH 8 #define MAX_PAYLOAD_LENGTH 20 #define PACKET_PREFIX_LENGTH 9 #define VALUE_PACKET_NAME_LEN_OFFSET 13 +#define DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET 17 // Packet Spec: @@ -27,6 +29,12 @@ using namespace pxt; // payload: buffer length (9), buffer (10 ... 28) #define PACKET_TYPE_BUFFER 3 +// payload: number (9 ... 16) +#define PACKET_TYPE_DOUBLE 4 + +// payload: number (9 ... 16), name length (17), name (18 ... 26) +#define PACKET_TYPE_DOUBLE_VALUE 5 + //% color=#E3008C weight=96 icon="\uf012" namespace radio { @@ -41,7 +49,8 @@ namespace radio { uint8_t type; uint32_t time; uint32_t serial; - int value; + int ivalue; + double dvalue; String msg; // may be NULL before first packet Buffer bufMsg; // may be NULL before first packet @@ -118,7 +127,7 @@ namespace radio { return mkBuffer(buf + 1, len); } - void writePacketAsJSON(uint8_t tp, int v, int s, int t, String m, Buffer b) { + void writePacketAsJSON(uint8_t tp, int iv, double dv, int s, int t, String m, Buffer b) { // Convert the packet to JSON and send over serial uBit.serial.send("{"); uBit.serial.send("\"t\":"); @@ -138,7 +147,13 @@ namespace radio { } if (tp == PACKET_TYPE_NUMBER || tp == PACKET_TYPE_VALUE) { uBit.serial.send(",\"v\":"); - uBit.serial.send(v); + uBit.serial.send(iv); + } else if (tp == PACKET_TYPE_DOUBLE || tp == PACKET_TYPE_DOUBLE_VALUE) { + uBit.serial.send(",\"v\":"); + TNumber td = fromDouble(dv); + String sd = numops::toString(td); + uBit.serial.send((uint8_t*)sd->data, sd->length); + decrRC(sd); } uBit.serial.send("}\r\n"); } @@ -155,7 +170,8 @@ namespace radio { uint8_t tp; int t; int s; - int v = 0; + int iv = 0; + double dv = 0; String m = NULL; Buffer b = NULL; @@ -163,17 +179,29 @@ namespace radio { memcpy(&t, buf + 1, 4); memcpy(&s, buf + 5, 4); - if (tp == PACKET_TYPE_STRING) { - m = getStringValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1); - } - else if (tp == PACKET_TYPE_BUFFER) { - b = getBufferValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1); - } - else { - memcpy(&v, buf + 9, 4); - if (tp == PACKET_TYPE_VALUE) { - m = getStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_NAME_LENGTH); - } + switch(tp) { + case PACKET_TYPE_STRING: + m = getStringValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1); + break; + case PACKET_TYPE_BUFFER: + b = getBufferValue(buf + PACKET_PREFIX_LENGTH, MAX_PAYLOAD_LENGTH - 1); + break; + case PACKET_TYPE_DOUBLE: + case PACKET_TYPE_DOUBLE_VALUE: + memcpy(&dv, buf + PACKET_PREFIX_LENGTH, sizeof(double)); + if (tp == PACKET_TYPE_DOUBLE_VALUE) { + m = getStringValue(buf + DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_DOUBLE_NAME_LENGTH); + } + break; + case PACKET_TYPE_NUMBER: + case PACKET_TYPE_VALUE: + memcpy(&iv, buf + PACKET_PREFIX_LENGTH, sizeof(int)); + if (tp == PACKET_TYPE_VALUE) { + m = getStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, MAX_FIELD_NAME_LENGTH); + } + break; + default: // unknown packet + return; } if (NULL == m) @@ -187,14 +215,15 @@ namespace radio { type = tp; time = t; serial = s; - value = v; + ivalue = iv; + dvalue = dv; decrRC(msg); decrRC(bufMsg); msg = m; bufMsg = b; } else { - writePacketAsJSON(tp, v, s, t, m, b); + writePacketAsJSON(tp, iv, dv, s, t, m, b); decrRC(m); decrRC(b); } @@ -206,16 +235,26 @@ namespace radio { //% help=radio/send-number //% weight=60 //% blockId=radio_datagram_send block="radio send number %value" blockGap=8 - void sendNumber(int value) { + void sendNumber(TNumber 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); + int iv = toInt(value); + double dv = toDouble(value); + if (iv == dv) { + uint8_t length = PACKET_PREFIX_LENGTH + sizeof(int); + uint8_t buf[length]; + memset(buf, 0, length); + setPacketPrefix(buf, PACKET_TYPE_NUMBER); + memcpy(buf + PACKET_PREFIX_LENGTH, &iv, sizeof(int)); + uBit.radio.datagram.send(buf, length); + } else { + uint8_t length = PACKET_PREFIX_LENGTH + sizeof(double); + uint8_t buf[length]; + memset(buf, 0, length); + setPacketPrefix(buf, PACKET_TYPE_DOUBLE); + memcpy(buf + PACKET_PREFIX_LENGTH, &dv, sizeof(double)); + uBit.radio.datagram.send(buf, length); + } } /** @@ -227,18 +266,27 @@ namespace radio { //% help=radio/send-value //% weight=59 //% blockId=radio_datagram_send_value block="radio send|value %name|= %value" blockGap=8 - void sendValue(String name, int value) { + void sendValue(String name, TNumber value) { if (radioEnable() != MICROBIT_OK) return; uint8_t buf[32]; memset(buf, 0, 32); - setPacketPrefix(buf, PACKET_TYPE_VALUE); - memcpy(buf + PACKET_PREFIX_LENGTH, &value, 4); + int iv = toInt(value); + double dv = toDouble(value); + if (iv == dv) { + setPacketPrefix(buf, PACKET_TYPE_VALUE); + memcpy(buf + PACKET_PREFIX_LENGTH, &iv, sizeof(int)); - int stringLen = copyStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_NAME_LENGTH); + int stringLen = copyStringValue(buf + VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_DOUBLE_NAME_LENGTH); + uBit.radio.datagram.send(buf, VALUE_PACKET_NAME_LEN_OFFSET + stringLen); + } else { + setPacketPrefix(buf, PACKET_TYPE_DOUBLE_VALUE); + memcpy(buf + PACKET_PREFIX_LENGTH, &dv, sizeof(double)); - uBit.radio.datagram.send(buf, VALUE_PACKET_NAME_LEN_OFFSET + stringLen); + int stringLen = copyStringValue(buf + DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET, name, MAX_FIELD_NAME_LENGTH); + uBit.radio.datagram.send(buf, DOUBLE_VALUE_PACKET_NAME_LEN_OFFSET + stringLen); + } } /** @@ -304,7 +352,16 @@ namespace radio { //% advanced=true void writeReceivedPacketToSerial() { if (radioEnable() != MICROBIT_OK) return; - writePacketAsJSON(type, value, (int) serial, (int) time, msg, bufMsg); + writePacketAsJSON(type, ivalue, dvalue, (int) serial, (int) time, msg, bufMsg); + } + + TNumber readNumber() { + if (type == PACKET_TYPE_NUMBER || type == PACKET_TYPE_VALUE) + return fromInt(ivalue); + else if (type == PACKET_TYPE_DOUBLE || type == PACKET_TYPE_DOUBLE_VALUE) + return fromDouble(dvalue); + else + return fromInt(0); } /** @@ -315,11 +372,11 @@ namespace radio { //% weight=46 //% blockId=radio_datagram_receive block="radio receive number" blockGap=8 //% deprecated=true - int receiveNumber() + TNumber receiveNumber() { if (radioEnable() != MICROBIT_OK) return 0; receivePacket(false); - return value; + return readNumber(); } /** @@ -333,7 +390,7 @@ namespace radio { if (radioEnable() != MICROBIT_OK) return; registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body); // make sure the receive buffer has a free spot - receiveNumber(); + receivePacket(false); } @@ -411,9 +468,9 @@ namespace radio { * contain a number. */ //% help=radio/received-number - int receivedNumber() { + TNumber receivedNumber() { if (radioEnable() != MICROBIT_OK) return 0; - return value; + return readNumber(); } /** diff --git a/libs/radio/shims.d.ts b/libs/radio/shims.d.ts index 7074db7e..babe10ff 100644 --- a/libs/radio/shims.d.ts +++ b/libs/radio/shims.d.ts @@ -21,7 +21,7 @@ declare namespace radio { //% help=radio/send-number //% weight=60 //% blockId=radio_datagram_send block="radio send number %value" blockGap=8 shim=radio::sendNumber - function sendNumber(value: int32): void; + function sendNumber(value: number): void; /** * Broadcasts a name / value pair along with the device serial number @@ -32,7 +32,7 @@ declare namespace radio { //% 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: int32): void; + function sendValue(name: string, value: number): void; /** * Broadcasts a string along with the device serial number @@ -81,7 +81,7 @@ declare namespace radio { //% weight=46 //% blockId=radio_datagram_receive block="radio receive number" blockGap=8 //% deprecated=true shim=radio::receiveNumber - function receiveNumber(): int32; + function receiveNumber(): number; /** * Registers code to run when a packet is received over radio. @@ -150,7 +150,7 @@ declare namespace radio { * contain a number. */ //% help=radio/received-number shim=radio::receivedNumber - function receivedNumber(): int32; + function receivedNumber(): number; /** * Returns the serial number of the sender micro:bit from the last packet taken