diff --git a/inc/MicroBitRadio.h b/inc/MicroBitRadio.h index 8e1c548..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. @@ -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" @@ -64,8 +66,8 @@ 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. uint8_t rssi; - 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. + 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. @@ -105,7 +107,7 @@ class MicroBitRadio : MicroBitComponent * * @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. @@ -172,7 +174,7 @@ class MicroBitRadio : MicroBitComponent * * @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. @@ -181,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 111e9c5..01269e4 100644 --- a/source/ble-services/MicroBitRadio.cpp +++ b/source/ble-services/MicroBitRadio.cpp @@ -118,7 +118,7 @@ int MicroBitRadio::setFrequencyBand(int band) * * @return a pointer to the current receive buffer */ -PacketBuffer* MicroBitRadio::getRxBuf() +FrameBuffer* MicroBitRadio::getRxBuf() { return rxBuf; } @@ -137,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; @@ -152,7 +155,7 @@ int MicroBitRadio::queueRxBuf() } else { - PacketBuffer *p = rxQueue; + FrameBuffer *p = rxQueue; while (p->next != NULL) p = p->next; @@ -214,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; @@ -352,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) { @@ -397,9 +400,9 @@ int MicroBitRadio::dataReady() * * @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) { @@ -417,7 +420,7 @@ PacketBuffer* MicroBitRadio::recv() * @param data The packet contents to transmit. * @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; 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;