Skip to content

Commit

Permalink
Merge pull request #29 from embedded-creations/callbackptr
Browse files Browse the repository at this point in the history
Allow for passing a custom pointer to callback function
  • Loading branch information
bakercp committed Oct 15, 2021
2 parents 840272c + 858ab2d commit 002b0f6
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 6 deletions.
115 changes: 115 additions & 0 deletions examples/PacketSerialReverseEchoClass/PacketSerialReverseEchoClass.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// Copyright (c) 2012 Christopher Baker <https://christopherbaker.net>
//
// SPDX-License-Identifier: MIT
//

// This example is PacketSerialReverseEcho modified to use PacketSerial from within a class

#include <PacketSerial.h>

// This function takes a byte buffer and reverses it.
void reverse(uint8_t* buffer, size_t size)
{
uint8_t tmp;

for (size_t i = 0; i < size / 2; i++)
{
tmp = buffer[i];
buffer[i] = buffer[size - i - 1];
buffer[size - i - 1] = tmp;
}
}

class EchoClass {
public:
void begin(unsigned long speed) {
// If we want to receive packets, we must specify a packet handler function.
// The packet handler is a custom function with a signature like the
// onPacketReceived function below.
myPacketSerial.setPacketHandler(&onPacketReceived, this);

myPacketSerial.begin(speed);
}

void loop() {
// The PacketSerial::update() method attempts to read in any incoming serial
// data and emits received and decoded packets via the packet handler
// function specified by the user in the void setup() function.
//
// The PacketSerial::update() method should be called once per loop(). Failure
// to call the PacketSerial::update() frequently enough may result in buffer
// serial overflows.
myPacketSerial.update();

// Check for a receive buffer overflow (optional).
if (myPacketSerial.overflow())
{
// Send an alert via a pin (e.g. make an overflow LED) or return a
// user-defined packet to the sender.
//
// Ultimately you may need to just increase your recieve buffer via the
// template parameters (see the README.md).
}
}

private:
// C-style callbacks can't use non-static methods, so we use a static method that receives "this" as the sender argument: https://wiki.c2.com/?VirtualStaticIdiom
static void onPacketReceived(const void* sender, const uint8_t* buffer, size_t size) {
((EchoClass*)sender)->onPacketReceived(buffer, size);
}

// This is our handler callback function.
// When an encoded packet is received and decoded, it will be delivered here.
// The `buffer` is a pointer to the decoded byte array. `size` is the number of
// bytes in the `buffer`.
void onPacketReceived(const uint8_t* buffer, size_t size) {
// In this example, we will simply reverse the contents of the array and send
// it back to the sender.

// Make a temporary buffer.
uint8_t tempBuffer[size];

// Copy the packet into our temporary buffer.
memcpy(tempBuffer, buffer, size);

// Reverse our temporaray buffer.
reverse(tempBuffer, size);

// Send the reversed buffer back to the sender. The send() method will encode
// the whole buffer as as single packet, set packet markers, etc.
// The `tempBuffer` is a pointer to the `tempBuffer` array and `size` is the
// number of bytes to send in the `tempBuffer`.
myPacketSerial.send(tempBuffer, size);
}

PacketSerial myPacketSerial;
};

// By default, PacketSerial automatically wraps the built-in `Serial` object.
// While it is still possible to use the Serial object directly, it is
// recommended that the user let the PacketSerial object manage all serial
// communication. Thus the user should not call Serial.write(), Serial.print(),
// etc. Additionally the user should not use the serialEvent() framework.
//
// By default, PacketSerial uses COBS encoding and has a 256 byte receive
// buffer. This can be adjusted by the user by replacing `PacketSerial` with
// a variation of the `PacketSerial_<COBS, 0, BufferSize>` template found in
// PacketSerial.h.

EchoClass myEchoClass;

void setup()
{
// We begin communication with our PacketSerial object by setting the
// communication speed in bits / second (baud).
myEchoClass.begin(115200);
}


void loop()
{
// Do your program-specific loop() work here as usual.

myEchoClass.loop();
}
49 changes: 43 additions & 6 deletions src/PacketSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class PacketSerial_
_receiveBufferIndex(0),
_stream(nullptr),
_onPacketFunction(nullptr),
_onPacketFunctionWithSender(nullptr)
_onPacketFunctionWithSender(nullptr),
_senderPtr(nullptr)
{
}

Expand Down Expand Up @@ -224,18 +225,23 @@ class PacketSerial_
_receiveBufferIndex,
_decodeBuffer);

// clear the index here so that the callback function can call update() if needed and receive more data
_receiveBufferIndex = 0;
_recieveBufferOverflow = false;

if (_onPacketFunction)
{
_onPacketFunction(_decodeBuffer, numDecoded);
}
else if (_onPacketFunctionWithSender)
{
_onPacketFunctionWithSender(this, _decodeBuffer, numDecoded);
_onPacketFunctionWithSender(_senderPtr, _decodeBuffer, numDecoded);
}
}

_receiveBufferIndex = 0;
_recieveBufferOverflow = false;
} else {
_receiveBufferIndex = 0;
_recieveBufferOverflow = false;
}
}
else
{
Expand Down Expand Up @@ -302,6 +308,7 @@ class PacketSerial_
{
_onPacketFunction = onPacketFunction;
_onPacketFunctionWithSender = nullptr;
_senderPtr = nullptr;
}

/// \brief Set the function that will receive decoded packets.
Expand Down Expand Up @@ -333,13 +340,42 @@ class PacketSerial_
///
/// myPacketSerial.setPacketHandler(&onPacketReceived);
///
/// You can also register an arbitrary void* pointer to be passed to your packet handler method.
/// This is most useful when PacketSerial is used inside a class, to pass a pointer to
/// the containing class:
///
/// class EchoClass {
/// public:
/// void begin(unsigned long speed) {
/// myPacketSerial.setPacketHandler(&onPacketReceived, this);
/// myPacketSerial.begin(speed);
/// }
///
/// // C-style callbacks can't use non-static methods,
/// // so we use a static method that receives "this" as the sender argument:
/// // https://wiki.c2.com/?VirtualStaticIdiom
/// static void onPacketReceived(const void* sender, const uint8_t* buffer, size_t size) {
/// ((EchoClass*)sender)->onPacketReceived(buffer, size);
/// }
///
/// void onPacketReceived(const uint8_t* buffer, size_t size) {
/// // we can now use myPacketSerial as needed here
/// }
///
/// PacketSerial myPacketSerial;
/// };
///
/// Setting a packet handler will remove all other packet handlers.
///
/// \param onPacketFunctionWithSender A pointer to the packet handler function.
void setPacketHandler(PacketHandlerFunctionWithSender onPacketFunctionWithSender)
/// \param senderPtr Optional pointer to a void* pointer, default argument will pass a pointer to the sending PacketSerial instance to the callback
void setPacketHandler(PacketHandlerFunctionWithSender onPacketFunctionWithSender, void * senderPtr = nullptr)
{
_onPacketFunction = nullptr;
_onPacketFunctionWithSender = onPacketFunctionWithSender;
_senderPtr = senderPtr;
// for backwards compatibility, the default _senderPtr is "this", but you can't use "this" as a default argument
if(!senderPtr) _senderPtr = this;
}

/// \brief Check to see if the receive buffer overflowed.
Expand Down Expand Up @@ -384,6 +420,7 @@ class PacketSerial_

PacketHandlerFunction _onPacketFunction = nullptr;
PacketHandlerFunctionWithSender _onPacketFunctionWithSender = nullptr;
void* _senderPtr = nullptr;
};


Expand Down

0 comments on commit 002b0f6

Please sign in to comment.