Universal Receiver
By running NWK_LAYERED
on twe_twelite.network
and NWK_SIMPLE
on twe_twelite.network2
in the MWX library, you can receive and interpret various types of packets, including Layered Tree Network packets (such as TWELITE PAL, ARIA).
However, radio packets must be on the same channel and have the same application ID.
main.cpp
setup()
, loop()
, and the received packet callback function on_rx_packet()
are described.
setup()
These objects are declared in pkt_handler.cpp
and initialized with pnew()
during setup()
. They mainly interpret the packet payload (data).
mwx::pnew(g_pkt_pal);
mwx::pnew(g_pkt_apptwelite);
mwx::pnew(g_pkt_actsamples);
mwx::pnew(g_pkt_unknown);
Two network objects are created. Always set the_twelite.network
to NWK_LAYERED
.
auto&& nwk_ly = the_twelite.network.use<NWK_LAYERED>();
auto&& nwk_sm = the_twelite.network2.use<NWK_SIMPLE>();
loop()
In this sample, the important process in loop()
is the .refresh()
operation performed approximately every 1 second. Only g_pkt_apptwelite().refresh()
performs the duplicate checker timeout processing. The other objects do nothing.
if (TickTimer.available()) {
static unsigned t;
if (!(++t & 0x3FF)) {
g_pkt_pal.refresh();
g_pkt_apptwelite.refresh();
g_pkt_actsamples.refresh();
g_pkt_unknown.refresh();
}
}
on_rx_packet()
void on_rx_packet(packet_rx& rx, bool_t &handled) {
auto type = rx.get_network_type();
bool b_handled = false;
// PAL
if (!b_handled
&& type == mwx::NETWORK::LAYERED
&& g_pkt_pal.analyze(rx, b_handled)
) {
g_pkt_pal.display(rx);
}
// Act samples
if (!b_handled
&& type == mwx::NETWORK::SIMPLE
&& g_pkt_actsamples.analyze(rx, b_handled)
) {
g_pkt_actsamples.display(rx);
}
// Standard application (e.g. App_Twelite)
if (!b_handled
&& type == mwx::NETWORK::NONE
&& g_pkt_apptwelite.analyze(rx, b_handled)
) {
g_pkt_apptwelite.display(rx);
}
// unknown
if (!b_handled) {
g_pkt_unknown.analyze(rx, b_handled);
g_pkt_unknown.display(rx);
}
}
This is the most important part of this sample code. The packet type is determined by auto type = rx.get_network_type();
.
mwx::NETWORK::LAYERED
: Packet ofNWK_LAYERED
Layered Tree Networkmwx::NETWORK::SIMPLE
: Packet ofNWK_SIMPLE
mwx::NETWORK::NONE
: No network (e.g. App_Twelite)- Others : Error or unsupported packets
In the case of mwx::NETWORK::NONE
, duplicate checker processing for the same packet that may be sent multiple times due to retransmissions is not performed internally by the MWX library. You need to implement these yourself. This sample provides dup_checker.hpp
and dup_checker.cpp
.
Packet interpretation refers to the packet_rx&
object which wraps tsRxDataApp*
. The packet_rx
class itself has no special functions; it only defines access methods to some information obtained from tsRxDataApp*
using get_psRxDataApp()
.
pkt_common.hpp
Defined to unify the interface of the packet interpretation part.
template <class D>
struct pkt_handler {
D& self() { return static_cast<D&>(*this); }
bool analyze(packet_rx& rx, bool &b_handled) {
return self().pkt.analyze(rx, b_handled);
}
void display(packet_rx& rx) {
Serial
<< crlf
<< format("!PKT_%s(%03d-%08x/S=%d/L=%03d/V=%04d)"
, self().get_label_packet_type()
, self().pkt.data.u8addr_src
, self().pkt.data.u32addr_src
, rx.get_psRxDataApp()->u8Seq
, rx.get_lqi()
, self().pkt.data.u16volt
);
self().disp_detail(rx);
}
void refresh() {
self()._refresh();
}
};
// packet analyzer for App_Twelite
class pkt_handler_apptwelite : public pkt_handler<pkt_handler_apptwelite> {
friend class pkt_handler<pkt_handler_apptwelite>;
pkt_apptwelite pkt;
void disp_detail(packet_rx& rx);
const char* get_label_packet_type() { return "AppTwelite"; }
void _refresh() { pkt.refresh(); }
public:
pkt_handler_apptwelite() : pkt() {}
};
analyze()
: Interpret the packet payload.display()
: Display packet information.refresh()
: Describes processing every 1 second.self()
: Casts to derived classD
.
Furthermore, the packet interpretation class (e.g. pkt_handler_apptwelite
above) contains a member object pkt
. The actual packet interpretation part is implemented in each analyze()
in pkt_???.cpp
.
pkt_???.hpp
, pkt_???.cpp
Packet interpretation parts for each packet type define analyze()
and data structure data
. The member data
is a struct inheriting the common struct PktDataCommon
. Using this common part, the code for serial output of packet data is succinctly written.
pkt_pal
Supports packets related to PAL. PAL packet structure has a complex data structure. Here, an implementation using EASTL containers is done.
_vect_pal_sensors
: Pool of_pal_sensor
objects. This object is a dedicated class used for intrusive map._map_pal_sensors
: Intrusive map structure for efficient search of sensor data.
Each time multiple data in one packet are added, entries are secured in _vect_pal_sensors
and values are stored. When all data in the packet are interpreted, _map_pal_sensors
keyed by sensor type is constructed.
dup_checker
Implements duplicate checker. The checker’s behavior can be customized by template parameters.
Template parameters
MODE
: SpecifyingMODE_REJECT_SAME_SEQ
excludes packets with the same sequence number. Used when packet order is rearranged.MODE_REJECT_OLDER_SEQ
adopts the newer number.TIMEOUT_ms
: Interval for initializing the duplicate database. Specifying1000
means data older than 1 second are erased. Packets previously excluded can be accepted again after the database is initialized.N_ENTRIES
: Maximum number of elements allocated in the data structure.N_BUCKET_HASH
: Maximum number of hash values. Specify a prime number. Decided based on the types of wireless nodes received.
Containers
_mmap_entries
: Intrusive hash multi-map structure. Search key is the wireless node serial number._vect_pool
: Fixed number (N_ENTRIES
) of elements allocated for use in the map structure._ring_vecant_idx
: Manages indexes of elements in_vect_pool
not used by_mmap_entries
. It is a ring buffer structure; when adding elements, one value is taken from the ring buffer, and when removing, it is returned.
Duplicate check
bool check_dup(uint32_t u32ser, uint16_t u16val, uint32_t u32_timestamp) {
// find entry by key:u32ser.
auto r = _mmap_entries.equal_range(u32ser);
...
}
To search data from the multi-map structure, call .equal_range()
. The obtained r
is an iterator enumerating elements with the same serial number.
Each element (_dup_checker_entry
) records timestamp and sequence number. Duplicate checking is done based on these values.