pxt-calliope/libs/microbit-radio/radio.cpp

237 lines
8.4 KiB
C++
Raw Normal View History

2016-04-07 21:52:02 +02:00
#include "pxt.h"
2016-04-03 02:34:06 +02:00
2016-04-07 21:52:02 +02:00
using namespace pxt;
2016-04-03 02:34:06 +02:00
#define MAX_FIELD_NAME_LENGTH 12
2016-04-03 02:34:06 +02:00
//% color=270 weight=34
namespace radio {
// -------------------------------------------------------------------------
// Radio
// -------------------------------------------------------------------------
bool radioEnabled = false;
bool transmitSerialNumber = false;
2016-04-03 02:34:06 +02:00
PacketBuffer packet;
int radioEnable() {
int r = uBit.radio.enable();
2016-04-16 07:41:30 +02:00
if (r != MICROBIT_OK) {
uBit.panic(43);
return r;
}
2016-04-03 02:34:06 +02:00
if (!radioEnabled) {
2016-04-07 21:52:02 +02:00
uBit.radio.setGroup(pxt::programHash());
2016-04-03 02:34:06 +02:00
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);
}
/**
* Broadcasts a number over radio to any connected micro:bit in the group.
*/
//% help=radio/send-number
//% weight=60
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_send block="radio send number %value" blockGap=8
void sendNumber(int value) {
if (radioEnable() != MICROBIT_OK) return;
uint32_t t = system_timer_current_time();
uint32_t sn = transmitSerialNumber ? microbit_serial_number() : 0;
uint32_t buf[] = { (uint32_t)value, t, sn };
uBit.radio.datagram.send((uint8_t*)buf, 3*sizeof(uint32_t));
2016-04-03 02:34:06 +02:00
}
/**
* Broadcasts a name / value pair along with the device serial number
2016-08-02 01:02:06 +02:00
* and running time to any connected micro:bit in the group.
* @param name the field name (max 12 characters), eg: "data"
* @param value the numberic value
*/
//% help=radio/send-value
//% weight=59
2016-08-02 01:02:06 +02:00
//% 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);
uint32_t t = system_timer_current_time();
uint32_t sn = transmitSerialNumber ? microbit_serial_number() : 0;
uint8_t buf[32];
uint32_t* buf32 = (uint32_t*)buf;
2016-07-21 10:54:53 +02:00
memset(buf, 0, 32);
buf32[0] = value; // 4 bytes: value
buf32[1] = t; // 4 bytes: running time
buf32[2] = sn; // 4 bytes: serial number
uint8_t len = min(MAX_FIELD_NAME_LENGTH, n.length()); // 1 byte: string length
if (len > 0) {
buf[12] = len; //
memcpy(buf + 13, n.toCharArray(), len); // 13-25: field name
}
uBit.radio.datagram.send(buf, 13 + len);
}
/**
* Broadcasts a number over radio to any connected micro:bit in the group.
*/
//% help=radio/send-string
//% weight=58
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_send_string block="radio send string %msg"
void sendString(StringData* msg) {
if (radioEnable() != MICROBIT_OK) return;
ManagedString s(msg);
if (s.length() > MICROBIT_RADIO_MAX_PACKET_SIZE)
s = s.substring(0, MICROBIT_RADIO_MAX_PACKET_SIZE);
uBit.radio.datagram.send(s);
}
/**
* Reads a value sent with `stream value` and writes it
* to the serial stream as JSON
*/
//% help=radio/write-value-to-serial
//% weight=3
2016-08-02 01:02:06 +02:00
//% blockId=radio_write_value_serial block="radio write value to serial"
void writeValueToSerial() {
if (radioEnable() != MICROBIT_OK) return;
PacketBuffer p = uBit.radio.datagram.recv();
2016-05-10 19:14:51 +02:00
int length = p.length();
uint8_t* bytes = p.getBytes();
int value;
2016-05-10 19:14:51 +02:00
uBit.serial.send("{");
if (length >= 4) {
memcpy(&value, bytes, 4);
uBit.serial.send("v:"); uBit.serial.send(value);
if(length >= 8) {
memcpy(&value, bytes + 4, 4);
uBit.serial.send(",t:"); uBit.serial.send(value);
if (length >= 12) {
memcpy(&value, bytes + 8, 4);
uBit.serial.send(",s:"); uBit.serial.send(value);
if (length >= 13) {
char name[MAX_FIELD_NAME_LENGTH+1];
uint8_t len = min(MAX_FIELD_NAME_LENGTH, bytes[12]);
memcpy(name, bytes + 13, len);
name[len] = 0;
uBit.serial.send(",n:\""); uBit.serial.send(name); uBit.serial.send("\"");
}
}
}
}
uBit.serial.send("}\r\n");
}
2016-04-03 02:34:06 +02:00
/**
* Registers code to run when a packet is received over radio.
*/
//% help=radio/on-data-received
//% weight=50
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_received_event block="radio on data received" blockGap=8
2016-04-03 02:34:06 +02:00
void onDataReceived(Action body) {
if (radioEnable() != MICROBIT_OK) return;
registerWithDal(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM, body);
}
/**
* Reads a number at a given index, between ``0`` and ``3``, from the packet received by ``receive number``. Not supported in simulator.
* @param index index of the number to read from 0 to 3. 1 eg
*/
//% help=radio/received-number-at
//% weight=45 debug=true
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_received_number_at block="radio receive number|at %VALUE" blockGap=8
2016-04-03 02:34:06 +02:00
int receivedNumberAt(int index) {
if (radioEnable() != MICROBIT_OK) return 0;
if (0 <= index && index < packet.length() / 4) {
// packet.getBytes() is not aligned
int r;
memcpy(&r, packet.getBytes() + index * 4, 4);
return r;
}
return 0;
}
/**
* Reads the next packet as a number from the radio queue.
*/
//% help=radio/receive-number
//% weight=46
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_receive block="radio receive number" blockGap=8
2016-04-03 02:34:06 +02:00
int receiveNumber()
{
if (radioEnable() != MICROBIT_OK) return 0;
packet = uBit.radio.datagram.recv();
return receivedNumberAt(0);
}
/**
* Reads the next packet as a string and returns it.
*/
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_receive_string block="radio receive string" blockGap=8
//% weight=44
//% help=radio/receive-string
StringData* receiveString() {
if (radioEnable() != MICROBIT_OK) return ManagedString().leakData();
packet = uBit.radio.datagram.recv();
return ManagedString(packet).leakData();
}
2016-04-03 02:34:06 +02:00
/**
* Gets the received signal strength indicator (RSSI) from the packet received by ``receive number``. Not supported in simulator.
* namespace=radio
*/
//% help=radio/received-signal-strength
//% weight=40
2016-08-02 01:02:06 +02:00
//% blockId=radio_datagram_rssi block="radio received signal strength"
2016-04-03 02:34:06 +02:00
int receivedSignalStrength() {
if (radioEnable() != MICROBIT_OK) return 0;
return packet.getRSSI();
}
/**
* 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
*/
//% help=radio/set-group
2016-08-02 01:02:06 +02:00
//% weight=10 blockGap=8
//% blockId=radio_set_group block="radio set group %ID"
2016-04-03 02:34:06 +02:00
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.
2016-06-19 14:15:13 +02:00
* @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. eg: 7
2016-04-03 02:34:06 +02:00
*/
//% help=radio/set-transmit-power
2016-08-02 01:02:06 +02:00
//% weight=9 blockGap=8
//% blockId=radio_set_transmit_power block="radio set transmit power %power"
2016-04-03 02:34:06 +02:00
void setTransmitPower(int power) {
if (radioEnable() != MICROBIT_OK) return;
uBit.radio.setTransmitPower(power);
}
/**
* Set the radio to transmit the serial number in each message.
*/
//% help=radio/set-transmit-serial-number
2016-08-02 01:02:06 +02:00
//% weight=8 blockGap=8
//% blockId=radio_set_transmit_serial_number block="radio set transmit serial number %transmit"
void setTransmitSerialNumber(bool transmit) {
transmitSerialNumber = transmit;
}
2016-04-03 02:34:06 +02:00
}