Skip to content

Commit 4bd4bd7

Browse files
Add XBeeWithCallbacks::waitFor()
This allows waiting for an arbitrary API response. Combined with a user-defined "matching" function, this allows e.g. waiting for a reply to a packet previously sent in a convenient way. The main work is done using a waitForInternal() method, so the actual waitFor() can be a template method (to allow passing a response object directly, without having to also pass a matching API id). The implementation could have been put inside waitFor() directly, but then you would end up with a complete copy of the method for each response type you wait for.
1 parent 67adb10 commit 4bd4bd7

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

XBee.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,129 @@ uint8_t XBeeWithCallbacks::matchStatus(uint8_t frameId) {
16971697
return 0xff;
16981698
}
16991699

1700+
bool XBeeWithCallbacks::waitForInternal(uint8_t apiId, void *response, uint16_t timeout, void *func, uintptr_t data) {
1701+
unsigned long start = millis();
1702+
do {
1703+
// Wait for a packet of the right type
1704+
if (loopTop()) {
1705+
if (getResponse().getApiId() == apiId) {
1706+
// If the type is right, call the right
1707+
// conversion function based on the
1708+
// ApiId and call the match function.
1709+
// Because the match function is
1710+
// essentially called in the same way,
1711+
// regardless of the subclass used, the
1712+
// compiler can reduce most of the below
1713+
// mess into a single piece of code
1714+
// (though for fully optimizing, the
1715+
// separate getXxxResponse() methods
1716+
// must be unified as well).
1717+
switch(apiId) {
1718+
case ZBTxStatusResponse::API_ID: {
1719+
ZBTxStatusResponse *r = (ZBTxStatusResponse*)response;
1720+
bool(*f)(ZBTxStatusResponse&,uintptr_t) = (bool(*)(ZBTxStatusResponse&,uintptr_t))func;
1721+
getResponse().getZBTxStatusResponse(*r);
1722+
if(!f || f(*r, data))
1723+
return true;
1724+
break;
1725+
}
1726+
case ZBRxResponse::API_ID: {
1727+
ZBRxResponse *r = (ZBRxResponse*)response;
1728+
bool(*f)(ZBRxResponse&,uintptr_t) = (bool(*)(ZBRxResponse&,uintptr_t))func;
1729+
getResponse().getZBRxResponse(*r);
1730+
if(!f || f(*r, data))
1731+
return true;
1732+
break;
1733+
}
1734+
case ZBExplicitRxResponse::API_ID: {
1735+
ZBExplicitRxResponse *r = (ZBExplicitRxResponse*)response;
1736+
bool(*f)(ZBExplicitRxResponse&,uintptr_t) = (bool(*)(ZBExplicitRxResponse&,uintptr_t))func;
1737+
getResponse().getZBExplicitRxResponse(*r);
1738+
if(!f || f(*r, data))
1739+
return true;
1740+
break;
1741+
}
1742+
case ZBRxIoSampleResponse::API_ID: {
1743+
ZBRxIoSampleResponse *r = (ZBRxIoSampleResponse*)response;
1744+
bool(*f)(ZBRxIoSampleResponse&,uintptr_t) = (bool(*)(ZBRxIoSampleResponse&,uintptr_t))func;
1745+
getResponse().getZBRxIoSampleResponse(*r);
1746+
if(!f || f(*r, data))
1747+
return true;
1748+
break;
1749+
}
1750+
case TxStatusResponse::API_ID: {
1751+
TxStatusResponse *r = (TxStatusResponse*)response;
1752+
bool(*f)(TxStatusResponse&,uintptr_t) = (bool(*)(TxStatusResponse&,uintptr_t))func;
1753+
getResponse().getTxStatusResponse(*r);
1754+
if(!f || f(*r, data))
1755+
return true;
1756+
break;
1757+
}
1758+
case Rx16Response::API_ID: {
1759+
Rx16Response *r = (Rx16Response*)response;
1760+
bool(*f)(Rx16Response&,uintptr_t) = (bool(*)(Rx16Response&,uintptr_t))func;
1761+
getResponse().getRx16Response(*r);
1762+
if(!f || f(*r, data))
1763+
return true;
1764+
break;
1765+
}
1766+
case Rx64Response::API_ID: {
1767+
Rx64Response *r = (Rx64Response*)response;
1768+
bool(*f)(Rx64Response&,uintptr_t) = (bool(*)(Rx64Response&,uintptr_t))func;
1769+
getResponse().getRx64Response(*r);
1770+
if(!f || f(*r, data))
1771+
return true;
1772+
break;
1773+
}
1774+
case Rx16IoSampleResponse::API_ID: {
1775+
Rx16IoSampleResponse *r = (Rx16IoSampleResponse*)response;
1776+
bool(*f)(Rx16IoSampleResponse&,uintptr_t) = (bool(*)(Rx16IoSampleResponse&,uintptr_t))func;
1777+
getResponse().getRx16IoSampleResponse(*r);
1778+
if(!f || f(*r, data))
1779+
return true;
1780+
break;
1781+
}
1782+
case Rx64IoSampleResponse::API_ID: {
1783+
Rx64IoSampleResponse *r = (Rx64IoSampleResponse*)response;
1784+
bool(*f)(Rx64IoSampleResponse&,uintptr_t) = (bool(*)(Rx64IoSampleResponse&,uintptr_t))func;
1785+
getResponse().getRx64IoSampleResponse(*r);
1786+
if(!f || f(*r, data))
1787+
return true;
1788+
break;
1789+
}
1790+
case ModemStatusResponse::API_ID: {
1791+
ModemStatusResponse *r = (ModemStatusResponse*)response;
1792+
bool(*f)(ModemStatusResponse&,uintptr_t) = (bool(*)(ModemStatusResponse&,uintptr_t))func;
1793+
getResponse().getModemStatusResponse(*r);
1794+
if(!f || f(*r, data))
1795+
return true;
1796+
break;
1797+
}
1798+
case AtCommandResponse::API_ID: {
1799+
AtCommandResponse *r = (AtCommandResponse*)response;
1800+
bool(*f)(AtCommandResponse&,uintptr_t) = (bool(*)(AtCommandResponse&,uintptr_t))func;
1801+
getResponse().getAtCommandResponse(*r);
1802+
if(!f || f(*r, data))
1803+
return true;
1804+
break;
1805+
}
1806+
case RemoteAtCommandResponse::API_ID: {
1807+
RemoteAtCommandResponse *r = (RemoteAtCommandResponse*)response;
1808+
bool(*f)(RemoteAtCommandResponse&,uintptr_t) = (bool(*)(RemoteAtCommandResponse&,uintptr_t))func;
1809+
getResponse().getRemoteAtCommandResponse(*r);
1810+
if(!f || f(*r, data))
1811+
return true;
1812+
break;
1813+
}
1814+
}
1815+
}
1816+
// Call regular callbacks
1817+
loopBottom();
1818+
}
1819+
} while (millis() - start < timeout);
1820+
return false;
1821+
}
1822+
17001823
uint8_t XBeeWithCallbacks::waitForStatus(uint8_t frameId, uint16_t timeout) {
17011824
unsigned long start = millis();
17021825
do {

XBee.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,31 @@ class XBeeWithCallbacks : public XBee {
887887
*/
888888
void loop();
889889

890+
/**
891+
* Wait for a API response of the given type, optionally
892+
* filtered by the given match function.
893+
*
894+
* If a match function is given it is called for every response
895+
* of the right type received, passing the response and the data
896+
* parameter passed to this method. If the function returns true
897+
* (or if no function was passed), waiting stops and this method
898+
* returns true. If the function returns false, waiting
899+
* continues. After the given timeout passes, this method
900+
* returns false.
901+
*
902+
* While waiting, any other responses received are passed to the
903+
* relevant callbacks, just as if calling loop() continuously
904+
* (except for the response sought, that one is only passed to
905+
* the OnResponse handler and no others).
906+
*
907+
* After this method returns, the response itself can still be
908+
* retrieved using getResponse() as normal.
909+
*/
910+
template <typename Response>
911+
bool waitFor(Response& response, uint16_t timeout, bool (*func)(Response&, uintptr_t) = NULL, uintptr_t data = 0) {
912+
return waitForInternal(Response::API_ID, &response, timeout, (void*)func, data);
913+
}
914+
890915
/**
891916
* Sends a XBeeRequest (TX packet) out the serial port, and wait
892917
* for a status response API frame (up until the given timeout).

0 commit comments

Comments
 (0)