PingPong
Send a PING wireless packet from one of the two serially connected TWELITEs and receive a PONG wireless packet back from the other.
how to use act
Required TWELITE
Two of any of the following.
TWELITE DIP connected to UART with TWELITE R products/TWE-Lite-DIP/index.html), etc.
Explanation of ACT
Include
Include <TWELITE>
in all ACTs. Here, the simple network <NWK_SIMPLE>
should be included.
Declaration section
Sample act common declarations
Prototype declarations for longer processes (sending and receiving), since they are made into functions
Variables for holding data in the application
セットアップ setup()
The general flow of the program is the initial setup of each section and the start of each section.
the_twelite
This object is the core class object for manipulating TWENET.
the_twelite
に設定を反映するには <<
を用います。
Use <<
to reflect the setting in the_twelite
.
TWENET::appid(APP_ID)
to specify the Application ID.TWENET::channel(CHANNEL)
to specify the channel.TWENET::rx_when_idle()
Specifies that the receive circuit is open.
The <<, >>
operator is originally a bit shift operator, but it is used differently from its meaning.
Next, register the network.
The first line is written in the same way as the board registration, specifying <>
as <NWK_SIMPLE>
.
The second line specifies <NWK_SIMPLE>
, specifying 0xFE
(WK_SIMPLE
is a Child Node with an unset ID).
The third line specifies the maximum number of relays. This explanation does not touch on relaying, but packets are relayed when operating with multiple units.
Execute the_twelite.begin()
at the end of the setup()
function.
Analogue
Class object that handles ADCs (analog-to-digital converters).
Initialization Analogue.setup()
. The parameter true
specifies to wait in place until the ADC circuit is stable.
To start the ADC, call Analogue.begin()
. The parameter is a bitmap corresponding to the pin to be ADC'd.
The pack_bits()
function is used to specify the bitmap. It is a function with variable number of arguments, each argument specifies a bit position to be set to 1. For example, pack_bits(1,3,5)
returns the binary value 101010
. This function has the constexpr
specification, so if the parameters are constants only, they are expanded to constants.
The parameters are specified as PIN_ANALOGUE::A1
(ADC0) and PIN_ANALOGUE::VCC
(module supply voltage).
The second parameter is specified as 50
, and the ADC operation is started by default with TickTimer, which is set to
Except for the first time, the ADC is started in an interrupt handler.
Buttons
Detects changes in DIO (digital input) values; Buttons only detect a change in value after the same value has been detected a certain number of times in order to reduce the effects of mechanical button chattering.
Initialization is done with Buttons.setup()
. The parameter 5 is the number of detections required to determine the value, but it is the maximum value that can be set. Internally, the internal memory is allocated based on this number.
The start is done with Buttons.begin()
The first parameter is the DIO to be detected. The second parameter is the number of detections required to determine the state. The third parameter is the detection interval. Since 10
is specified, the HIGH and LOW states are determined when the same value is detected five times in a row every 10 ms.
The detection of the DIO state in Buttons is done by an event handler. Event handlers are called in the application loop after an interrupt has occurred, so there is a delay compared to interrupt handlers.
Serial
Serial objects can be used without initialization or initiation procedures.
Outputs a string to the serial port. mwx::crlf
is a newline character.
loop()
Loop function are called as callback functions from the main loop of the TWENET library. The basic description here is to wait for the object to be used to become available and then process it. This section describes the use of some objects used in ACT.
The main loop of the TWENET library processes incoming packets and interrupt information stored in the FIFO queue in advance as events, after which loop()
is called. After exiting loop()
, the CPU enters DOZE mode and waits until a new interrupt occurs with low current consumption.
Therefore, code that assumes the CPU is always running will not work well.
Serial
While Serial.available()
is true
, there is input from the serial port. The data is stored in the internal FIFO queue, so there is some leeway, but it should be read out promptly. To read data, call Serial.read()
.
Here, the vTransmit()
function is called to send a PING packet in response to a 't'
key input.
Buttons
It becomes available at the timing when a change in DIO (digital IO) input is detected, and is read by Buttons.read()
.
The first parameter is a bitmap of the HIGH/LOW of the current DIO, ordered from bit0 to DIO0,1,2,... . and so on, starting from bit 0. For example, for DIO12, HIGH / LOW can be determined by evaluating btn_state & (1UL << 12)
. If the bit is set to 1, it is HIGH.
When the IO state is determined for the first time, MSB (bit31) is set to 1. The initial determination process is also performed when the device returns from sleep.
The vTransmit()
is called at the timing when the button is released except for the initial confirmation. To make the timing of the press (! (btn_state && (1UL << PIN_BTN)))
to invert the condition logically.
transmit()
This function requests TWENET to send a wireless packet. At the end of this function, the wireless packet is not yet processed. The actual transmission will be completed in a few ms or later, depending on the transmission parameters. This section describes typical transmission request methods.
Getting Network and Packet Objects
Get a network object with the_twelite.network.use<NWK_SIMPLE>()
. Use that object to get a pkt
object by .prepare_tx_packet()
.
Here it is declared in the conditional expression of the if statement. The declared pkt
object is valid until the end of the if clause. pkt object gives a response of type bool, which here is true
if there is a free space in TWENET's send request queue and the send request is accepted, or false
if there is no space.
Settings for sending packets
Packets are configured using the <<
operator as in the_twelite
initialization setup.
Specify the destination address in the
tx_addr()
parameter. If it is0x00
, it means that you are the Child Node and broadcast to the Parent Node, and if it is0xFE
, it means that you are the Parent Node and broadcast to any Child Node.The
tx_retry()
parameter specifies the number of retransmissions. In the example3
means that the number of retransmissions is 3, i.e., the packet is sent 4 times in total. Sending only one wireless packet may fail a few percent of the time even under good conditions.tx_packet_delay()
Sets the transmission delay. The first parameter is the minimum wait time to start sending and the second is the maximum wait time. The third is the retransmission interval. The third is the retransmission interval, meaning that a retransmission is performed every 20 ms after the first packet is sent.
Data Payload in a Packet
Payload means a loaded item, but in wireless packets it is often used to mean "the main body of data to be sent". In addition to the main body of data, the data in a wireless packet also contains some auxiliary information, such as address information.
For correct transmission and reception, please be aware of the data order of the data payload. In this example, the data order is as follows. Construct the data payload according to this data order.
The data payload can contain 90 bytes (actually a few more bytes).
Every byte in an IEEE802.15.4 wireless packet is precious. There is a limit to the amount of data that can be sent in a single packet. If a packet is split, the cost of the split packet is high because it must take into account transmission failures. Also, sending one extra byte consumes energy equivalent to approximately 16 µs x current during transmission, which can be significant, especially for battery-powered applications. {endhint %}
Let's actually build the data structure of the above data payload. The data payload can be referenced as a container of type simplbuf<uint8_t>
via pkt.get_payload()
. In this container, we build the data based on the above specification.
It can be written as above, but the MWX library provides an auxiliary function pack_bytes()
for data payload construction.
The first parameter of pack_bytes
specifies the container. In this case, it is pkt.get_payload()
.
The parameters after that are variable arguments, specifying as many values of the corresponding type in pack_bytes
as needed. The pack_bytes
internally calls the .push_back()
method to append the specified value at the end.
The third line, make_pair()
, is a standard library function to generate std::pair
. This is specified to avoid confusion of string types (specifically, whether or not to include null characters when storing payloads). The first parameter of make_pair()
is the string type (char*
, uint8_t*
, uint8_t[]
, etc.) The second parameter is the number of bytes to store in the payload.
Lines 4, 5, and 6 store values of numeric types (uint8_t
, uint16_t
, uint32_t
). Numeric types such as signed, or even the same numeric type such as char
are cast to the three types listed on the left and submitted.
analogRead()
and analogRead_mv()
get the result of ADC. The former is the ADC value (0..1023) and the latter is the voltage[mv](0..2470). The supply voltage of the module is read internally from the value of the voltage divider resistor, so we use adalogRead_mv()
to perform that conversion.
This completes the packet preparation. Now all that remains is to make a request for transmission.
Packets are sent using the pkt.transmit()
method of the pkt
object.
Although not used in this ACT, the return value contains information about the success or failure of the request and the number corresponding to the request. Use this return value if the process waits until the transmission is complete.
on_rx_packet()
This is the process when there is an incoming packet.
First, the data of the incoming packet is passed as parameter rx
. From rx
, the address information and data payload of the wireless packet is accessed.
In the next line, the received packet data refers to the source address (32-bit long address and 8-bit logical address) and other information.
In <NWK_SIMPLE>
, two types of addresses are always exchanged: an 8-bit logical ID and a 32-bit long address. When specifying the destination, either the long address or the logical address is specified. When receiving, both addresses are included.
The MWX library provides a function expand_bytes()
as a counterpart to pack_bytes()
used in transmit()
.
Lines 1 through 3 specify variables to store data.
The first parameter specifies the first iterator of the container (a uint8_t*
pointer), which can be retrieved by the .begin()
method. The second parameter is the next iterator after the end of the container and can be retrieved with the .end()
method.
The third and subsequent parameters enumerate variables. The payloads are read and stored in the order in which they are listed.
This ACT omits error checking, such as if the packet length is wrong. If you want to make the check strict, judge by the return value of expand_bytes()
.
The return value of expand_bytes()
is uint8_t*
, but returns nullptr (null pointer)
in case of access beyond the end.
The process sends a PONG message if the identifier of the 4-byte string read in msg
is "PING"
.
It then displays information on packets that have arrived.
The format()
is used because numeric formatting output is required. helper class that allows the same syntax as printf() for >>
operators, but limits the number of arguments to a maximum of 8 (for 32-bit parameters). (A compile error will occur if the limit is exceeded. Note that Serial.printfmt()
has no limit on the number of arguments.)
The mwx::crlf
specifies a newline character (CR LF), and mwx::flush
waits for completion of output. (mxw::flush
may be written as Serial.flush()
)
最終更新