diff --git a/inc/MicroBitRadio.h b/inc/MicroBitRadio.h index d34263f..825332d 100644 --- a/inc/MicroBitRadio.h +++ b/inc/MicroBitRadio.h @@ -2,6 +2,7 @@ #define MICROBIT_RADIO_H #include "mbed.h" +#include "PacketBuffer.h" /** * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module. @@ -9,7 +10,7 @@ * The nrf51822 RADIO module supports a number of proprietary modes of operation in addition to the typical BLE usage. * This class uses one of these modes to enable simple, point to multipoint communication directly between micro:bits. * - * TODO: The protocols implemented here do not currently perform any significant form of energy management, + * TODO: The protocols implemented here do not currently perform any significant form of energy management, * which means that they will consume far more energy than their BLE equivalent. Later versions of the protocol * should look to address this through energy efficient broadcast techniques / sleep scheduling. In particular, the GLOSSY * approach to efficienct rebroadcast and network synchronisation would likely provide an effective future step. @@ -17,7 +18,7 @@ * TODO: Meshing should also be considered - again a GLOSSY approach may be effective here, and highly complementary to * the master/slave arachitecture of BLE. * - * TODO: This implementation only operates whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow + * TODO: This implementation only operates whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow * BLE to cohabit with other protocols. Future work to allow this colocation would be benefical, and would also allow for the * creation of wireless BLE bridges. * @@ -31,12 +32,12 @@ // Default configuration values #define MICROBIT_RADIO_BASE_ADDRESS 0x75626974 -#define MICROBIT_RADIO_DEFAULT_GROUP 0 +#define MICROBIT_RADIO_DEFAULT_GROUP 0 #define MICROBIT_RADIO_DEFAULT_TX_POWER 6 #define MICROBIT_RADIO_DEFAULT_FREQUENCY 7 -#define MICROBIT_RADIO_MAX_PACKET_SIZE 32 -#define MICROBIT_RADIO_HEADER_SIZE 4 -#define MICROBIT_RADIO_MAXIMUM_RX_BUFFERS 4 +#define MICROBIT_RADIO_MAX_PACKET_SIZE 32 +#define MICROBIT_RADIO_HEADER_SIZE 4 +#define MICROBIT_RADIO_MAXIMUM_RX_BUFFERS 4 // Known Protocol Numbers #define MICROBIT_RADIO_PROTOCOL_DATAGRAM 1 // A simple, single frame datagram. a little like UDP but with smaller packets. :-) @@ -45,7 +46,7 @@ // Events #define MICROBIT_RADIO_EVT_DATAGRAM 1 // Event to signal that a new datagram has been received. -struct PacketBuffer +struct FrameBuffer { uint8_t length; // The length of the remaining bytes in the packet. includes protocol/version/group fields, excluding the length field itself. uint8_t version; // Protocol version code. @@ -53,7 +54,8 @@ struct PacketBuffer uint8_t protocol; // Inner protocol number c.f. those issued by IANA for IP protocols uint8_t payload[MICROBIT_RADIO_MAX_PACKET_SIZE]; // User / higher layer protocol data - PacketBuffer *next; // Linkage, to allow this and other protocols to queue packets pending processing. + FrameBuffer *next; // Linkage, to allow this and other protocols to queue packets pending processing. + uint8_t rssi; // Received signal strength of this frame. }; #include "MicroBitRadioDatagram.h" @@ -63,8 +65,9 @@ class MicroBitRadio : MicroBitComponent { uint8_t group; // The radio group to which this micro:bit belongs. uint8_t queueDepth; // The number of packets in the receiver queue. - PacketBuffer *rxQueue; // A linear list of incoming packets, queued awaiting processing. - PacketBuffer *rxBuf; // A pointer to the buffer being actively used by the RADIO hardware. + uint8_t rssi; + FrameBuffer *rxQueue; // A linear list of incoming packets, queued awaiting processing. + FrameBuffer *rxBuf; // A pointer to the buffer being actively used by the RADIO hardware. public: MicroBitRadioDatagram datagram; // A simple datagram service. @@ -74,7 +77,7 @@ class MicroBitRadio : MicroBitComponent /** * Constructor. * - * Initialise the MicroBitRadio. Note that this class is demand activated, so most resources are only + * Initialise the MicroBitRadio. Note that this class is demand activated, so most resources are only * committed if send/recv or event registrations calls are made. */ MicroBitRadio(uint16_t id); @@ -82,7 +85,7 @@ class MicroBitRadio : MicroBitComponent /** * 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. + * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range. * */ @@ -92,7 +95,7 @@ class MicroBitRadio : MicroBitComponent * Change the transmission and reception band of the radio to the given channel * * @param band a frequency band in the range 0 - 100. Each step is 1MHz wide, based at 2400MHz. - * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range, + * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range, * or MICROBIT_NOT_SUPPORTED if the BLE stack is running. * */ @@ -102,9 +105,9 @@ class MicroBitRadio : MicroBitComponent * Retrieve a pointer to the currently allocated recieve buffer. This is the area of memory * actively being used by the radio hardware to store incoming data. * - * @return a pointer to the current receive buffer + * @return a pointer to the current receive buffer */ - PacketBuffer* getRxBuf(); + FrameBuffer * getRxBuf(); /** * Attempt to queue a buffer received by the radio hardware, if sufficient space is available. @@ -115,7 +118,19 @@ class MicroBitRadio : MicroBitComponent int queueRxBuf(); /** - * Initialises the radio for use as a multipoint sender/receiver + * Sets the RSSI for the most recent packet. + * + * @param rssi the new rssi value + */ + int setRSSI(uint8_t rssi); + + /** + * Retrieves the current RSSI for the most recent packet. + */ + int getRSSI(); + + /** + * Initialises the radio for use as a multipoint sender/receiver * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if SoftDevice is enabled. */ int enable(); @@ -138,7 +153,7 @@ class MicroBitRadio : MicroBitComponent * A background, low priority callback that is triggered whenever the processor is idle. * Here, we empty our queue of received packets, and pass them onto higher level protocol handlers. * - * We provide optimised handling of well known, simple protocols and events on the MicroBitMessageBus + * We provide optimised handling of well known, simple protocols and events on the MicroBitMessageBus * to provide extensibility to other protocols that may be written in the future. */ virtual void idleTick(); @@ -152,14 +167,14 @@ class MicroBitRadio : MicroBitComponent /** * Retrieves the next packet from the receive buffer. * If a data packet is available, then it will be returned immediately to - * the caller. This call will also dequeue the buffer. + * the caller. This call will also dequeue the buffer. * - * NOTE: Once recv() has been called, it is the callers resposibility to + * NOTE: Once recv() has been called, it is the callers resposibility to * delete the buffer when appropriate. * * @return The buffer containing the the packet. If no data is available, NULL is returned. */ - PacketBuffer* recv(); + FrameBuffer* recv(); /** * Transmits the given buffer onto the broadcast radio. @@ -168,7 +183,7 @@ class MicroBitRadio : MicroBitComponent * @param data The packet contents to transmit. * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running. */ - int send(PacketBuffer *buffer); + int send(FrameBuffer *buffer); }; #endif diff --git a/inc/MicroBitRadioDatagram.h b/inc/MicroBitRadioDatagram.h index 1521e72..71b60d9 100644 --- a/inc/MicroBitRadioDatagram.h +++ b/inc/MicroBitRadioDatagram.h @@ -18,7 +18,7 @@ class MicroBitRadioDatagram { - PacketBuffer *rxQueue; // A linear list of incoming packets, queued awaiting processing. + FrameBuffer *rxQueue; // A linear list of incoming packets, queued awaiting processing. public: @@ -46,7 +46,7 @@ class MicroBitRadioDatagram * * @return the data received, or the EmptyString if no data is available. */ - ManagedString recv(); + PacketBuffer recv(); /** * Transmits the given buffer onto the broadcast radio. @@ -65,7 +65,7 @@ class MicroBitRadioDatagram * @param data The packet contents to transmit. * @return MICROBIT_OK on success. */ - int send(ManagedString data); + int send(PacketBuffer data); /** * Protocol handler callback. This is called when the radio receives a packet marked as a datagram. diff --git a/inc/PacketBuffer.h b/inc/PacketBuffer.h new file mode 100644 index 0000000..7ef932f --- /dev/null +++ b/inc/PacketBuffer.h @@ -0,0 +1,239 @@ +#ifndef MICROBIT_PACKET_BUFFER_H +#define MICROBIT_PACKET_BUFFER_H + +#include "mbed.h" +#include "RefCounted.h" + +struct PacketData : RefCounted +{ + uint16_t rssi; // The radio signal strength this packet was received. + uint8_t length; // The length of the payload in bytes + uint8_t payload[0]; // User / higher layer protocol data +}; + +/** + * Class definition for a PacketBuffer. + * A PacketBuffer holds a series of bytes that can be sent or received from the MicroBitRadio channel. + * n.b. This is a mutable, managed type. + */ +class PacketBuffer +{ + PacketData *ptr; // Pointer to payload data + + public: + + /** + * Provide an array containing the packet data. + * @return The contents of this packet, as an array of bytes. + */ + uint8_t *getBytes(); + + /** + * Default Constructor. + * Creates an empty Packet Buffer. + * + * Example: + * @code + * PacketBuffer p(); + * @endcode + */ + PacketBuffer(); + + /** + * Constructor. + * Creates a new PacketBuffer of the given size. + * + * @param length The length of the buffer to create. + * + * Example: + * @code + * PacketBuffer p(16); // Creates a PacketBuffer 16 bytes long. + * @endcode + */ + PacketBuffer(int length); + + /** + * Constructor. + * Creates an empty Packet Buffer of the given size, + * and fills it with the data provided. + * + * @param data The data with which to fill the buffer. + * @param length The length of the buffer to create. + * @param rssi The radio signal strength at the time this pacer was recieved. + * + * Example: + * @code + * uint8_t buf = {13,5,2}; + * PacketBuffer p(buf, 3); // Creates a PacketBuffer 3 bytes long. + * @endcode + */ + PacketBuffer(uint8_t *data, int length, int rssi = 0); + + /** + * Copy Constructor. + * Add ourselves as a reference to an existing PacketBuffer. + * + * @param buffer The PacketBuffer to reference. + * + * Example: + * @code + * PacketBuffer p(); + * PacketBuffer p2(i); // Refers to the same packet as p. + * @endcode + */ + PacketBuffer(const PacketBuffer &buffer); + + /** + * Internal constructor-initialiser. + * + * @param data The data with which to fill the buffer. + * @param length The length of the buffer to create. + * @param rssi The radio signal strength at the time this packet was recieved. + * + */ + void init(uint8_t *data, int length, int rssi); + + /** + * Destructor. + * Removes buffer resources held by the instance. + */ + ~PacketBuffer(); + + /** + * Copy assign operation. + * + * Called when one PacketBuffer is assigned the value of another using the '=' operator. + * Decrements our reference count and free up the buffer as necessary. + * Then, update our buffer to refer to that of the supplied PacketBuffer, + * and increase its reference count. + * + * @param p The PacketBuffer to reference. + * + * Example: + * @code + * uint8_t buf = {13,5,2}; + * PacketBuffer p1(16); + * PacketBuffer p2(buf, 3); + * + * p1 = p2; + * @endcode + */ + PacketBuffer& operator = (const PacketBuffer& p); + + /** + * Array access operation (read). + * + * Called when a PacketBuffer is dereferenced with a [] operation. + * Transparently map this through to the underlying payload for elegance of programming. + * + * Example: + * @code + * PacketBuffer p1(16); + * uint8_t data = p1[0]; + * @endcode + */ + uint8_t operator [] (int i) const; + + /** + * Array access operation (modify). + * + * Called when a PacketBuffer is dereferenced with a [] operation. + * Transparently map this through to the underlying payload for elegance of programming. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1[0] = 42; + * @endcode + */ + uint8_t& operator [] (int i); + + /** + * Equality operation. + * + * Called when one PacketBuffer is tested to be equal to another using the '==' operator. + * + * @param p The PacketBuffer to test ourselves against. + * @return true if this PacketBuffer is identical to the one supplied, false otherwise. + * + * Example: + * @code + * + * uint8_t buf = {13,5,2}; + * PacketBuffer p1(16); + * PacketBuffer p2(buf, 3); + * + * if(p1 == p2) // will be true + * uBit.display.scroll("same!"); + * @endcode + */ + bool operator== (const PacketBuffer& p); + + /** + * Sets the byte at the given index to value provided. + * @param position The index of the byte to change. + * @param value The new value of the byte (0-255). + * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. + * @endcode + */ + int setByte(int position, uint8_t value); + + /** + * Determines the value of the given byte in the packet. + * + * @param position The index of the byte to read. + * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. + * p1.getByte(0); // Returns 255. + * @endcode + */ + int getByte(int position); + + /** + * Gets number of bytes in this buffer + * @return The size of the buffer in bytes. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.length(); // Returns 16. + * @endcode + */ + int length(); + + /** + * Gets the received signal strength of this packet. + * + * @return The signal strength of the radio when this packet was received, in -dbM. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.getRSSI(); // Returns the received signal strength. + * @endcode + */ + int getRSSI(); + + /** + * Sets the received signal strength of this packet. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.setRSSI(37); + * @endcode + */ + void setRSSI(uint8_t rssi); +}; + +#endif + diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 8134b7e..59ece8e 100755 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -33,6 +33,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES "RefCounted.cpp" "MemberFunctionCallback.cpp" "MicroBitStorage.cpp" + "PacketBuffer.cpp" "ble-services/MicroBitBLEManager.cpp" "ble-services/MicroBitDFUService.cpp" "ble-services/MicroBitEventService.cpp" diff --git a/source/PacketBuffer.cpp b/source/PacketBuffer.cpp new file mode 100644 index 0000000..32cb783 --- /dev/null +++ b/source/PacketBuffer.cpp @@ -0,0 +1,296 @@ +#include "MicroBit.h" + +/** + * Default Constructor. + * Creates an empty Packet Buffer. + * + * Example: + * @code + * PacketBuffer p(); + * @endcode + */ +PacketBuffer::PacketBuffer() +{ + this->init(NULL, 0, 0); +} + +/** + * Constructor. + * Creates an empty Packet Buffer of the given size. + * + * @param length The length of the buffer to create. + * + * Example: + * @code + * PacketBuffer p(16); // Creates a PacketBuffer 16 bytes long. + * @endcode + */ +PacketBuffer::PacketBuffer(int length) +{ + this->init(NULL, length, 0); +} + +/** + * Constructor. + * Creates a new PacketBuffer of the given size, + * and fills it with the data provided. + * + * @param data The data with which to fill the buffer. + * @param length The length of the buffer to create. + * @param rssi The radio signal strength at the time this packet was recieved. + * + * Example: + * @code + * uint8_t buf = {13,5,2}; + * PacketBuffer p(buf, 3); // Creates a PacketBuffer 3 bytes long. + * @endcode + */ +PacketBuffer::PacketBuffer(uint8_t *data, int length, int rssi) +{ + this->init(data, length, rssi); +} + +/** + * Copy Constructor. + * Add ourselves as a reference to an existing PacketBuffer. + * + * @param buffer The PacketBuffer to reference. + * + * Example: + * @code + * PacketBuffer p(); + * PacketBuffer p2(i); // Refers to the same packet as p. + * @endcode + */ +PacketBuffer::PacketBuffer(const PacketBuffer &buffer) +{ + ptr = buffer.ptr; + ptr->incr(); +} + +/** + * Internal constructor-initialiser. + * + * @param data The data with which to fill the buffer. + * @param length The length of the buffer to create. + * @param rssi The radio signal strength at the time this pacer was recieved. + * + */ +void PacketBuffer::init(uint8_t *data, int length, int rssi) +{ + if (length < 0) + length = 0; + + ptr = (PacketData *) malloc(sizeof(PacketData) + length); + ptr->init(); + + ptr->length = length; + ptr->rssi = rssi; + + // Copy in the data buffer, if provided. + if (data) + memcpy(ptr->payload, data, length); +} + +/** + * Destructor. + * Removes buffer resources held by the instance. + */ +PacketBuffer::~PacketBuffer() +{ + ptr->decr(); +} + +/** + * Copy assign operation. + * + * Called when one PacketBuffer is assigned the value of another using the '=' operator. + * Decrements our reference count and free up the buffer as necessary. + * Then, update our buffer to refer to that of the supplied PacketBuffer, + * and increase its reference count. + * + * @param p The PacketBuffer to reference. + * + * Example: + * @code + * uint8_t buf = {13,5,2}; + * PacketBuffer p1(16); + * PacketBuffer p2(buf, 3); + * + * p1 = p2; + * @endcode + */ +PacketBuffer& PacketBuffer::operator = (const PacketBuffer &p) +{ + if(ptr == p.ptr) + return *this; + + ptr->decr(); + ptr = p.ptr; + ptr->incr(); + + return *this; +} + +/** + * Array access operation (read). + * + * Called when a PacketBuffer is dereferenced with a [] operation. + * Transparently map this through to the underlying payload for elegance of programming. + * + * Example: + * @code + * PacketBuffer p1(16); + * uint8_t data = p1[0]; + * @endcode + */ +uint8_t PacketBuffer::operator [] (int i) const +{ + return ptr->payload[i]; +} + +/** + * Array access operation (modify). + * + * Called when a PacketBuffer is dereferenced with a [] operation. + * Transparently map this through to the underlying payload for elegance of programming. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1[0] = 42; + * @endcode + */ +uint8_t& PacketBuffer::operator [] (int i) +{ + return ptr->payload[i]; +} + +/** + * Equality operation. + * + * Called when one PacketBuffer is tested to be equal to another using the '==' operator. + * + * @param p The PacketBuffer to test ourselves against. + * @return true if this PacketBuffer is identical to the one supplied, false otherwise. + * + * Example: + * @code + * + * uint8_t buf = {13,5,2}; + * PacketBuffer p1(16); + * PacketBuffer p2(buf, 3); + * + * if(p1 == p2) // will be true + * uBit.display.scroll("same!"); + * @endcode + */ +bool PacketBuffer::operator== (const PacketBuffer& p) +{ + if (ptr == p.ptr) + return true; + else + return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length)==0)); +} + +/** + * Sets the byte at the given index to value provided. + * @param position The index of the byte to change. + * @param value The new value of the byte (0-255). + * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.setByte(0,255); // Sets the firts byte in the buffer to the value 255. + * @endcode + */ +int PacketBuffer::setByte(int position, uint8_t value) +{ + if (position < ptr->length) + { + ptr->payload[position] = value; + return MICROBIT_OK; + } + else + { + return MICROBIT_INVALID_PARAMETER; + } +} + +/** + * Determines the value of the given byte in the packet. + * + * @param position The index of the byte to read. + * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.setByte(0,255); // Sets the firts byte in the buffer to the value 255. + * p1.getByte(0); // Returns 255. + * @endcode + */ +int PacketBuffer::getByte(int position) +{ + if (position < ptr->length) + return ptr->payload[position]; + else + return MICROBIT_INVALID_PARAMETER; +} + +/** + * Provide an array containing the packet data. + * @return The contents of this packet, as an array of bytes. + */ +uint8_t*PacketBuffer::getBytes() +{ + return ptr->payload; +} + +/** + * Gets number of bytes in this buffer + * @return The size of the buffer in bytes. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.length(); // Returns 16. + * @endcode + */ +int PacketBuffer::length() +{ + return ptr->length; +} + +/** + * Gets the received signal strength of this packet. + * + * @return The signal strength of the radio when this packet was received. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.getRSSI(); + * @endcode + */ +int PacketBuffer::getRSSI() +{ + return ptr->rssi; +} + +/** + * Sets the received signal strength of this packet. + * + * Example: + * @code + * PacketBuffer p1(16); + * p1.setRSSI(37); + * @endcode + */ +void PacketBuffer::setRSSI(uint8_t rssi) +{ + ptr->rssi = rssi; +} + + diff --git a/source/ble-services/MicroBitRadio.cpp b/source/ble-services/MicroBitRadio.cpp index e118182..01269e4 100644 --- a/source/ble-services/MicroBitRadio.cpp +++ b/source/ble-services/MicroBitRadio.cpp @@ -6,7 +6,7 @@ * The nrf51822 RADIO module supports a number of proprietary modes of operation oher than the typical BLE usage. * This class uses one of these modes to enable simple, point to multipoint communication directly between micro:bits. * - * TODO: The protocols implemented here do not currently perform any significant form of energy management, + * TODO: The protocols implemented here do not currently perform any significant form of energy management, * which means that they will consume far more energy than their BLE equivalent. Later versions of the protocol * should look to address this through energy efficient broadcast techbiques / sleep scheduling. In particular, the GLOSSY * approach to efficient rebroadcast and network synchronisation would likely provide an effective future step. @@ -14,7 +14,7 @@ * TODO: Meshing should also be considered - again a GLOSSY approach may be effective here, and highly complementary to * the master/slave arachitecture of BLE. * - * TODO: This implementation may only operated whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow + * TODO: This implementation may only operated whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow * BLE to cohabit with other protocols. Future work to allow this colocation would be benefical, and would also allow for the * creation of wireless BLE bridges. * @@ -31,15 +31,34 @@ extern "C" void RADIO_IRQHandler(void) MicroBitRadio::instance->queueRxBuf(); NRF_RADIO->PACKETPTR = (uint32_t) MicroBitRadio::instance->getRxBuf(); - // Start listening for the next packet. - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->TASKS_START = 1; + if(NRF_RADIO->EVENTS_READY) + { + NRF_RADIO->EVENTS_READY = 0; + + // Start listening and wait for the END event + NRF_RADIO->TASKS_START = 1; + } + + if(NRF_RADIO->EVENTS_END) + { + NRF_RADIO->EVENTS_END = 0; + + if(NRF_RADIO->CRCSTATUS == 1) + { + uint8_t sample = NRF_RADIO->RSSISAMPLE; + + uBit.radio.setRSSI(sample); + } + + // Start listening and wait for the END event + NRF_RADIO->TASKS_START = 1; + } } /** * Constructor. * - * Initialise the MicroBitRadio. Note that this class is demand activated, so most resources are only committed + * Initialise the MicroBitRadio. Note that this class is demand activated, so most resources are only committed * if send/recv or event registrations calls are made. */ MicroBitRadio::MicroBitRadio(uint16_t id) : datagram() @@ -48,6 +67,7 @@ MicroBitRadio::MicroBitRadio(uint16_t id) : datagram() this->status = 0; this->group = 0; this->queueDepth = 0; + this->rssi = 0; this->rxQueue = NULL; this->rxBuf = NULL; @@ -57,7 +77,7 @@ MicroBitRadio::MicroBitRadio(uint16_t id) : datagram() /** * 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. + * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range. * */ @@ -75,7 +95,7 @@ int MicroBitRadio::setTransmitPower(int power) * Change the transmission and reception band of the radio to the given channel * * @param band a frequency band in the range 0 - 100. Each step is 1MHz wide, based at 2400MHz. - * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range, + * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range, * or MICROBIT_NOT_SUPPORTED if the BLE stack is running. * */ @@ -96,9 +116,9 @@ int MicroBitRadio::setFrequencyBand(int band) * Retrieve a pointer to the currently allocated receive buffer. This is the area of memory * actively being used by the radio hardware to store incoming data. * - * @return a pointer to the current receive buffer + * @return a pointer to the current receive buffer */ -PacketBuffer* MicroBitRadio::getRxBuf() +FrameBuffer* MicroBitRadio::getRxBuf() { return rxBuf; } @@ -117,8 +137,11 @@ int MicroBitRadio::queueRxBuf() if (queueDepth >= MICROBIT_RADIO_MAXIMUM_RX_BUFFERS) return MICROBIT_NO_RESOURCES; + // Store the received RSSI value in the frame + rxBuf->rssi = getRSSI(); + // Ensure that a replacement buffer is available before queuing. - PacketBuffer *newRxBuf = new PacketBuffer(); + FrameBuffer *newRxBuf = new FrameBuffer(); if (newRxBuf == NULL) return MICROBIT_NO_RESOURCES; @@ -132,7 +155,7 @@ int MicroBitRadio::queueRxBuf() } else { - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; while (p->next != NULL) p = p->next; @@ -148,6 +171,34 @@ int MicroBitRadio::queueRxBuf() return MICROBIT_OK; } +/** + * Sets the RSSI for the most recent packet. + * + * @param rssi the new rssi value + * + * @note should only be called from RADIO_IRQHandler... + */ +int MicroBitRadio::setRSSI(uint8_t rssi) +{ + if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) + return MICROBIT_NOT_SUPPORTED; + + this->rssi = rssi; + + return MICROBIT_OK; +} + +/** + * Retrieves the current RSSI for the most recent packet. + */ +int MicroBitRadio::getRSSI() +{ + if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) + return MICROBIT_NOT_SUPPORTED; + + return this->rssi; +} + /** * Initialises the radio for use as a multipoint sender/receiver. * This is currently only possible if the BLE stack (Soft Device) is disabled. @@ -166,7 +217,7 @@ int MicroBitRadio::enable() // If this is the first time we've been enable, allocate out receive buffers. if (rxBuf == NULL) - rxBuf = new PacketBuffer(); + rxBuf = new FrameBuffer(); if (rxBuf == NULL) return MICROBIT_NO_RESOURCES; @@ -181,15 +232,15 @@ int MicroBitRadio::enable() setTransmitPower(MICROBIT_RADIO_DEFAULT_TX_POWER); setFrequencyBand(MICROBIT_RADIO_DEFAULT_FREQUENCY); - // Configure for 1Mbps throughput. + // Configure for 1Mbps throughput. // This may sound excessive, but running a high data rates reduces the chances of collisions... NRF_RADIO->MODE = RADIO_MODE_MODE_Nrf_1Mbit; // Configure the addresses we use for this protocol. We run ANONYMOUSLY at the core. - // A 40 bit addresses is used. The first 32 bits match the ASCII character code for "uBit". + // A 40 bit addresses is used. The first 32 bits match the ASCII character code for "uBit". // Statistically, this provides assurance to avoid other similar 2.4GHz protocols that may be in the vicinity. - // We also map the assigned 8-bit GROUP id into the PREFIX field. This allows the RADIO hardware to perform - // address matching for us, and only generate an interrupt when a packet matching our group is received. + // We also map the assigned 8-bit GROUP id into the PREFIX field. This allows the RADIO hardware to perform + // address matching for us, and only generate an interrupt when a packet matching our group is received. NRF_RADIO->BASE0 = MICROBIT_RADIO_BASE_ADDRESS; // Join the default group. This will configure the remaining byte in the RADIO hardware module. @@ -197,8 +248,8 @@ int MicroBitRadio::enable() // The RADIO hardware module supports the use of multiple addresses, but as we're running anonymously, we only need one. // Configure the RADIO module to use the default address (address 0) for both send and receive operations. - NRF_RADIO->TXADDRESS = 0; - NRF_RADIO->RXADDRESSES = 1; + NRF_RADIO->TXADDRESS = 0; + NRF_RADIO->RXADDRESSES = 1; // Packet layout configuration. The nrf51822 has a highly capable and flexible RADIO module that, in addition to transmission // and reception of data, also contains a LENGTH field, two optional additional 1 byte fields (S0 and S1) and a CRC calculation. @@ -212,21 +263,23 @@ int MicroBitRadio::enable() // and we know we can't trust it. The nrf51822 RADIO uses a CRC for this - a very effective checksum calculation. // // Enable automatic 16bit CRC generation and checking, and configure how the CRC is calculated. - NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two; - NRF_RADIO->CRCINIT = 0xFFFF; - NRF_RADIO->CRCPOLY = 0x11021; + NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two; + NRF_RADIO->CRCINIT = 0xFFFF; + NRF_RADIO->CRCPOLY = 0x11021; // Set the start random value of the data whitening algorithm. This can be any non zero number. - NRF_RADIO->DATAWHITEIV = 0x18; + NRF_RADIO->DATAWHITEIV = 0x18; - // Set up the RADIO module to read and write from our internal buffer. - NRF_RADIO->PACKETPTR = (uint32_t)rxBuf; + // Set up the RADIO module to read and write from our internal buffer. + NRF_RADIO->PACKETPTR = (uint32_t)rxBuf; // Configure the hardware to issue an interrupt whenever a task is complete (e.g. send/receive). NRF_RADIO->INTENSET = 0x00000008; NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); - + + NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_RSSISTART_Msk; + // Start listening for the next packet NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->TASKS_RXEN = 1; @@ -253,7 +306,7 @@ int MicroBitRadio::disable() // Only attempt to enable.disable the radio if the protocol is alreayd running. if (uBit.ble) return MICROBIT_NOT_SUPPORTED; - + if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) return MICROBIT_OK; @@ -294,7 +347,7 @@ int MicroBitRadio::setGroup(uint8_t group) * A background, low priority callback that is triggered whenever the processor is idle. * Here, we empty our queue of received packets, and pass them onto higher level protocol handlers. * - * We provide optimised handling of well known, simple protocols and events on the MicroBitMessageBus + * We provide optimised handling of well known, simple protocols and events on the MicroBitMessageBus * to provide extensibility to other protocols that may be written in the future. */ void MicroBitRadio::idleTick() @@ -302,7 +355,7 @@ void MicroBitRadio::idleTick() // Walk the list of packets and process each one. while(rxQueue) { - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; switch (p->protocol) { @@ -314,11 +367,11 @@ void MicroBitRadio::idleTick() event.packetReceived(); break; - default: + default: MicroBitEvent(MICROBIT_ID_RADIO_DATA_READY, p->protocol); } - // If the packet was processed, it will have been recv'd, and taken from the queue. + // If the packet was processed, it will have been recv'd, and taken from the queue. // If this was a packet for an unknown protocol, it will still be there, so simply free it. if (p == rxQueue) { @@ -340,16 +393,16 @@ int MicroBitRadio::dataReady() /** * Retrieves the next packet from the receive buffer. * If a data packet is available, then it will be returned immediately to - * the caller. This call will also dequeue the buffer. + * the caller. This call will also dequeue the buffer. * - * NOTE: Once recv() has been called, it is the callers resposibility to + * NOTE: Once recv() has been called, it is the callers resposibility to * delete the buffer when appropriate. * * @return The buffer containing the the packet. If no data is available, NULL is returned. */ -PacketBuffer* MicroBitRadio::recv() +FrameBuffer* MicroBitRadio::recv() { - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; if (p) { @@ -365,9 +418,9 @@ PacketBuffer* MicroBitRadio::recv() * 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, or MICROBIT_NOT_SUPPORTED if the BLE stack is running. + * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running. */ -int MicroBitRadio::send(PacketBuffer *buffer) +int MicroBitRadio::send(FrameBuffer *buffer) { if (uBit.ble) return MICROBIT_NOT_SUPPORTED; @@ -421,4 +474,3 @@ int MicroBitRadio::send(PacketBuffer *buffer) return MICROBIT_OK; } - diff --git a/source/ble-services/MicroBitRadioDatagram.cpp b/source/ble-services/MicroBitRadioDatagram.cpp index d8d185e..c6727fd 100644 --- a/source/ble-services/MicroBitRadioDatagram.cpp +++ b/source/ble-services/MicroBitRadioDatagram.cpp @@ -36,7 +36,7 @@ int MicroBitRadioDatagram::recv(uint8_t *buf, int len) return MICROBIT_INVALID_PARAMETER; // Take the first buffer from the queue. - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; rxQueue = rxQueue->next; int l = min(len, p->length - (MICROBIT_RADIO_HEADER_SIZE - 1)); @@ -55,15 +55,15 @@ int MicroBitRadioDatagram::recv(uint8_t *buf, int len) * * @return the data received, or the EmptyString if no data is available. */ -ManagedString MicroBitRadioDatagram::recv() +PacketBuffer MicroBitRadioDatagram::recv() { - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; rxQueue = rxQueue->next; - ManagedString s((const char *)p->payload, p->length - (MICROBIT_RADIO_HEADER_SIZE - 1)); + PacketBuffer packet(p->payload, p->length - (MICROBIT_RADIO_HEADER_SIZE - 1), p->rssi); delete p; - return s; + return packet; } /** @@ -79,7 +79,7 @@ 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; + FrameBuffer buf; buf.length = len + MICROBIT_RADIO_HEADER_SIZE - 1; buf.version = 1; @@ -97,9 +97,9 @@ int MicroBitRadioDatagram::send(uint8_t *buffer, int len) * @param data The packet contents to transmit. * @return MICROBIT_OK on success. */ -int MicroBitRadioDatagram::send(ManagedString data) +int MicroBitRadioDatagram::send(PacketBuffer data) { - return send((uint8_t *)data.toCharArray(), data.length()); + return send((uint8_t *)data.getBytes(), data.length()); } /** @@ -108,7 +108,7 @@ int MicroBitRadioDatagram::send(ManagedString data) */ void MicroBitRadioDatagram::packetReceived() { - PacketBuffer *packet = uBit.radio.recv(); + FrameBuffer *packet = uBit.radio.recv(); int queueDepth = 0; // We add to the tail of the queue to preserve causal ordering. @@ -120,7 +120,7 @@ void MicroBitRadioDatagram::packetReceived() } else { - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; while (p->next != NULL) { p = p->next; diff --git a/source/ble-services/MicroBitRadioEvent.cpp b/source/ble-services/MicroBitRadioEvent.cpp index e3a1bec..4a9d445 100644 --- a/source/ble-services/MicroBitRadioEvent.cpp +++ b/source/ble-services/MicroBitRadioEvent.cpp @@ -55,7 +55,7 @@ int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value) */ void MicroBitRadioEvent::packetReceived() { - PacketBuffer *p = uBit.radio.recv(); + FrameBuffer *p = uBit.radio.recv(); MicroBitEvent *e = (MicroBitEvent *) p->payload; suppressForwarding = true; @@ -75,7 +75,7 @@ void MicroBitRadioEvent::eventReceived(MicroBitEvent e) if(suppressForwarding) return; - PacketBuffer buf; + FrameBuffer buf; buf.length = sizeof(MicroBitEvent) + MICROBIT_RADIO_HEADER_SIZE - 1; buf.version = 1;