142 lines
4.3 KiB
C++
142 lines
4.3 KiB
C++
#include "MicroBit.h"
|
|
|
|
/**
|
|
* Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
|
|
*
|
|
* This class provides the ability to broadcast simple text or binary messages to other micro:bits in the vicinity
|
|
* It is envisaged that this would provide the basis for children to experiment with building their own, simple,
|
|
* custom protocols.
|
|
*
|
|
* NOTE: This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a
|
|
* teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
|
|
* For serious applications, BLE should be considered a substantially more secure alternative.
|
|
*/
|
|
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
MicroBitRadioDatagram::MicroBitRadioDatagram()
|
|
{
|
|
rxQueue = NULL;
|
|
}
|
|
|
|
/**
|
|
* Retreives packet payload data into the given buffer.
|
|
* If a data packet is already available, then it will be returned immediately to the caller.
|
|
* If no data is available the EmptyString is returned, then MICROBIT_INVALID_PARAMETER is returned.
|
|
*
|
|
* @param buf A pointer to a valid memory location where the received data is to be stored.
|
|
* @param len The maximum amount of data that can safely be stored in 'buf'
|
|
*
|
|
* @return The length of the data stored, or MICROBIT_INVALID_PARAMETER if no data is available, or the memory regions provided are invalid.
|
|
*/
|
|
int MicroBitRadioDatagram::recv(uint8_t *buf, int len)
|
|
{
|
|
if (buf == NULL || rxQueue == NULL || len < 0)
|
|
return MICROBIT_INVALID_PARAMETER;
|
|
|
|
// Take the first buffer from the queue.
|
|
PacketBuffer *p = rxQueue;
|
|
rxQueue = rxQueue->next;
|
|
|
|
int l = min(len, p->length - MICROBIT_RADIO_HEADER_SIZE - 1);
|
|
|
|
// Fill in the buffer provided, if possible.
|
|
memcpy(buf, p->payload, l);
|
|
|
|
delete p;
|
|
return l;
|
|
}
|
|
|
|
/**
|
|
* Retreives packet payload data into the given buffer.
|
|
* If a data packet is already available, then it will be returned immediately to the caller,
|
|
* in the form of a string. If no data is available the EmptyString is returned.
|
|
*
|
|
* @return the data received, or the EmptyString if no data is available.
|
|
*/
|
|
ManagedString MicroBitRadioDatagram::recv()
|
|
{
|
|
PacketBuffer *p = rxQueue;
|
|
rxQueue = rxQueue->next;
|
|
|
|
ManagedString s((const char *)p->payload, p->length - MICROBIT_RADIO_HEADER_SIZE - 1);
|
|
|
|
delete p;
|
|
return s;
|
|
}
|
|
|
|
/**
|
|
* Transmits the given buffer onto the broadcast radio.
|
|
* The call will wait until the transmission of the packet has completed before returning.
|
|
*
|
|
* @param buffer The packet contents to transmit.
|
|
* @param len The number of bytes to transmit.
|
|
* @return MICROBIT_OK on success.
|
|
*/
|
|
int MicroBitRadioDatagram::send(uint8_t *buffer, int len)
|
|
{
|
|
if (buffer == NULL || len < 0 || len > MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE - 1)
|
|
return MICROBIT_INVALID_PARAMETER;
|
|
|
|
PacketBuffer buf;
|
|
|
|
buf.length = len + MICROBIT_RADIO_HEADER_SIZE - 1;
|
|
buf.version = 1;
|
|
buf.group = 0;
|
|
buf.protocol = MICROBIT_RADIO_PROTOCOL_DATAGRAM;
|
|
memcpy(buf.payload, buffer, len);
|
|
|
|
return uBit.radio.send(&buf);
|
|
}
|
|
|
|
/**
|
|
* Transmits the given string onto the broadcast radio.
|
|
* The call will wait until the transmission of the packet has completed before returning.
|
|
*
|
|
* @param data The packet contents to transmit.
|
|
* @return MICROBIT_OK on success.
|
|
*/
|
|
int MicroBitRadioDatagram::send(ManagedString data)
|
|
{
|
|
return send((uint8_t *)data.toCharArray(), data.length());
|
|
}
|
|
|
|
/**
|
|
* Protocol handler callback. This is called when the radio receives a packet marked as a datagram.
|
|
* This function process this packet, and queues it for user reception.
|
|
*/
|
|
void MicroBitRadioDatagram::packetReceived()
|
|
{
|
|
PacketBuffer *packet = uBit.radio.recv();
|
|
int queueDepth = 0;
|
|
|
|
// We add to the tail of the queue to preserve causal ordering.
|
|
packet->next = NULL;
|
|
|
|
if (rxQueue == NULL)
|
|
{
|
|
rxQueue = packet;
|
|
}
|
|
else
|
|
{
|
|
PacketBuffer *p = rxQueue;
|
|
while (p->next != NULL)
|
|
{
|
|
p = p->next;
|
|
queueDepth++;
|
|
}
|
|
|
|
if (queueDepth >= MICROBIT_RADIO_MAXIMUM_RX_BUFFERS)
|
|
{
|
|
delete packet;
|
|
return;
|
|
}
|
|
|
|
p->next = packet;
|
|
}
|
|
|
|
MicroBitEvent(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM);
|
|
}
|
|
|