This is the multi-page printable view of this section. Click here to print...
API Reference
- 1: MWX Library
- 1.1: MWX Library
- 1.1.1: General
- 1.1.1.1: License
- 1.1.1.2: Terminology
- 1.1.1.3: Design Information
- 1.1.2: Definitions
- 1.1.3: Class Objects
- 1.1.3.1: the_twelite
- 1.1.3.2: Analogue
- 1.1.3.3: Buttons
- 1.1.3.4: EEPROM
- 1.1.3.5: PulseCounter
- 1.1.3.6: Serial
- 1.1.3.7: SerialParser
- 1.1.3.8: SPI
- 1.1.3.8.1: SPI (Member Function Version)
- 1.1.3.8.2: SPI (Helper Class Version)
- 1.1.3.9: TickTimer
- 1.1.3.10: Timer0 .. 4
- 1.1.3.11: Wire
- 1.1.3.11.1: Wire (Member Function Version)
- 1.1.3.11.2: Wire (Helper Class Version)
- 1.1.4: Classes
- 1.1.4.1: MWX_APIRET
- 1.1.4.2: alloc
- 1.1.4.3: axis_xyzt
- 1.1.4.4: packet_rx
- 1.1.4.5: packet_tx
- 1.1.4.6: serparser
- 1.1.4.7: pktparser
- 1.1.4.7.1: E_PKT
- 1.1.4.7.2: identify_packet_type()
- 1.1.4.7.3: TwePacket
- 1.1.4.7.3.1: TwePacketTwelite
- 1.1.4.7.3.2: TwePacketIO
- 1.1.4.7.3.3: TwePacketUART
- 1.1.4.7.3.4: TwePacketPAL
- 1.1.4.8: smplbuf
- 1.1.4.8.1: get_stream_helper()
- 1.1.4.8.2: smplbuf_strm_u8
- 1.1.4.9: smplque
- 1.1.4.10: Input/Output Stream
- 1.1.4.10.1: mwx::mwx_format
- 1.1.4.10.2: mwx::bigendian
- 1.1.4.10.3: mwx::crlf
- 1.1.4.10.4: mwx::flush
- 1.1.4.10.5: stream_helper
- 1.1.4.11: SM_SIMPLE State Machine
- 1.1.5: Callback Functions
- 1.1.5.1: setup()
- 1.1.5.2: begin()
- 1.1.5.3: loop()
- 1.1.5.4: wakeup()
- 1.1.5.5: init_coldboot()
- 1.1.5.6: init_warmboot()
- 1.1.5.7: on_rx_packet()
- 1.1.5.8: on_tx_comp()
- 1.1.6: Behavior
- 1.1.6.1: PAL_AMB-behavior
- 1.1.7: Functions
- 1.1.7.1: System Functions
- 1.1.7.1.1: millis()
- 1.1.7.1.2: delay()
- 1.1.7.1.3: delayMicroseconds()
- 1.1.7.1.4: random()
- 1.1.7.2: General Purpose Digital IO
- 1.1.7.2.1: pinMode()
- 1.1.7.2.2: digitalWrite()
- 1.1.7.2.3: digitalRead()
- 1.1.7.2.4: attachIntDio()
- 1.1.7.2.5: detachIntDio()
- 1.1.7.2.6: digitalReadBitmap()
- 1.1.7.3: Utility Functions
- 1.1.7.3.1: Printf Implementation
- 1.1.7.3.2: pack_bits()
- 1.1.7.3.3: collect_bits()
- 1.1.7.3.4: Byte array utils
- 1.1.7.3.5: pack_bytes()
- 1.1.7.3.6: expand-bytes()
- 1.1.7.3.7: CRC8, XOR, LRC
- 1.1.7.3.8: div10(), div100(), div1000()
- 1.1.7.3.9: Scale utils
- 1.1.7.3.10: pnew()
- 1.1.8: External Libraries
- 1.1.8.1: EASTL
- 1.1.9: Board Behavior (BRD)
- 1.1.9.1: <BRD_APPTWELITE>
- 1.1.9.2: PAL Common Definitions
- 1.1.9.2.1: <PAL_NOTICE>
- 1.1.9.2.2: <PAL_AMB>
- 1.1.9.2.3: <PAL_MAG>
- 1.1.9.2.4: <PAL_MOT>
- 1.1.9.3: <ARIA>
- 1.1.9.4: <CUE>
- 1.1.9.5: <MONOSTICK>
- 1.1.10: Sensor Devices (SNS)
- 1.1.10.1: SHTC3
- 1.1.10.2: SHT3x
- 1.1.10.3: LTR-308ALS
- 1.1.10.4: MC3630
- 1.1.10.5: BMx280
- 1.1.10.6: PCA9632
- 1.1.10.7: SHT4x
- 1.1.11: Network Behavior (NWK)
- 1.1.11.1: Simple Relay Network <NWK_SIMPLE>
- 1.1.11.2: <NWK_LAYERED>
- 1.1.12: Configuration Interface by Setting Behavior
- 1.1.12.1: <STG_STD>
- 2: TWELITE SDK / MWSDK (Legacy)
- 3: TWELITE Wings API / MWings
- 3.1: TWELITE Wings API / MWings for 32-bit Arduinos
- 3.1.1: TWELITE Wings API / MWings for 32-bit Arduinos
- 3.1.1.1: List of Data Types and Procedures
- 3.1.1.2: Class List
- 3.1.1.2.1: mwings::MWings Class
- 3.2: TWELITE Wings API / MWings for Python
- 3.2.1: TWELITE Wings API / MWings for Python
- 3.2.1.1: mwings module
- 3.2.1.1.1: mwings.common Module
- 3.2.1.1.2: mwings.parsers Module
- 3.2.1.1.2.1: mwings.parsers.app_twelite Module
- 3.2.1.1.2.2: mwings.parsers.app_io Module
- 3.2.1.1.2.3: mwings.parsers.app_aria Module
- 3.2.1.1.2.4: mwings.parsers.app_cue Module
- 3.2.1.1.2.5: mwings.parsers.app_cue_pal_event Module
- 3.2.1.1.2.6: mwings.parsers.app_pal_openclose Module
- 3.2.1.1.2.7: mwings.parsers.app_pal_amb Module
- 3.2.1.1.2.8: mwings.parsers.app_pal_mot Module
- 3.2.1.1.2.9: mwings.parsers.app_uart_ascii Module
- 3.2.1.1.2.10: mwings.parsers.app_uart_ascii_extended Module
- 3.2.1.1.2.11: mwings.parsers.act Module
- 3.2.1.1.3: mwings.serializers Module
- 3.2.1.1.3.1: mwings.serializers.app_twelite Module
- 3.2.1.1.3.2: mwings.serializers.app_io Module
- 3.2.1.1.3.3: mwings.serializers.app_pal_notice Module
- 3.2.1.1.3.4: mwings.serializers.app_pal_notice_detailed Module
- 3.2.1.1.3.5: mwings.serializers.app_pal_notice_event Module
- 3.2.1.1.3.6: mwings.serializers.app_uart_ascii Module
- 3.2.1.1.4: mwings.utils Module
1 - MWX Library
1.1 - MWX Library
For document handling policies, please refer to About These Documents.
If you notice anything incorrect or unclear, please contact us via the Support Form.
1.1.1 - General
+-----------------------+
| act (USER APPs)... |
+-----------------------+
| MWX C++ LIB |
+---------------+ |
| TWENET C LIB | |
+------------+----------+
| MAC LAYER | AHI APIs |
+-----------------------+
| TWELITE HARDWARE |
+-----------------------+
The name of the MWX library is Mono Wireless C++ Library for TWELITE. “MW” comes from MonoWireless, and “C++” → “CXX” → double X → “WX”. By overlapping this MW and WX, it became MWX. Code written using this library is called “act”.
Notations
This section describes the notations used in this explanation.
auto&&
Called a universal reference, it is often used in the standard library. In this library as well, auto&&
is used in most cases.
auto
in C language is a keyword used to declare local variables (automatic variables), but here it means declaration by type inference. In C++ template syntax, type names often become very complicated, and it is convenient when you can implement without explicitly specifying the type name.
The example below uses the standard library algorithm std::minmax_element
to find the minimum and maximum values of the type of v
, and the return value is declared with auto
. In this case, the type inferred by auto
is std::pair<int, int>
.
#include <algorithm>
int v[] = { 1, 3, -1, 5, 10 };
auto&& result = std::minmax_element(std::begin(v), std::end(v));
Serial << "min=" << int(result.first)
<< ",max=" << int(result.second);
You need to refer to specialized books for the strict meaning of &&
in auto &&
, but here, think of it as “whether the return is a reference type (similar to pointer passing in C) or a value, you can declare it without worrying.”
About namespaces
namespace
, inline namespace
, and using
are used to redefine names. Some parts are omitted even in the explanation.
Limitations (TWENET)
The MWX library is not developed with the purpose of supporting all the underlying libraries and functions (functions in the TWENET C library, microcontroller peripheral functions provided by semiconductor vendors, IEEE802.15.4 functions).
Limitations (Use of C++)
The MWX library is written in C++ and the act is also written in C++. However, not all features of C++ can be used. Please note the following points especially.
- Memory allocation with
new
andnew[]
operators is possible, but the allocated memory cannot be freed. Most dynamic memory allocations in C++ libraries are practically unusable. - Constructors of global objects are not called.
- Note: If necessary, you can initialize including constructor calls by initializing in the setup function (
setup()
) likenew ((void*)&obj_global) class_foo();
. - Exceptions (
exception
) cannot be used. - Virtual functions (
virtual
) cannot be used. - Due to the above restrictions, only part of the C++ standard library such as STL can be used.
※ This is based on what we are aware of.
About the Library Source Code
The source code can be referenced from the following.
{MWSDK installation folder}/TWENET/current/src/mwx
- https://github.com/monowireless/mwx
1.1.1.1 - License
Warranty and License
Unless otherwise noted, the contents of this package are subject to either the MONO WIRELESS Software License Agreement (MW-SLA) or the MONO WIRELESS Open Source Software License Agreement (MW-OSSLA).
This document is also considered part of the library package and is covered under the MW-SLA.
This software is not officially supported by MONO WIRELESS Co., Ltd. We may not be able to respond to inquiries. Thank you for your understanding.
MONO WIRELESS Co., Ltd. does not guarantee fixes or improvements in response to bug reports.
Please note that functionality may also be affected by your environment, such as the installation package or other system dependencies.
1.1.1.2 - Terminology
General Terminology
SDK (TWELITE SDK, MWSDK)
Software Development Kit (SDK)
IEEE802.15.4
A wireless standard used by TWELITE wireless modules. As long as you are using the MWX library, you generally do not need to be concerned with the details of the protocol.
Packet
The smallest unit of transmission in wireless communication. The maximum size varies depending on the communication method and settings, but in MWX’s standard <NWK_SIMPLE> communication, up to 90 bytes can be transmitted in one packet.
Payload
While the literal meaning is “cargo”, it refers to the actual data content included in a wireless packet.
Node
Literally means “point” or “junction”, but in this context it refers to a wireless device within a wireless network.
MWX Library-Specific Terminology
Act
A program created using this library. Refers to either the source code or the running program.
Behavior
A program written in an event-driven style, defined within an Act. Refers to either the source code or the running program.
A behavior is written as a single class definition that encapsulates callbacks from TWENET, events, and interrupt handling. MWX defines three types of behaviors:
- Application Behavior: A user-defined class that describes application logic in an event-driven format.
- Board Behavior: A class that simplifies usage of functions provided by the TWELITE module board.
- Network Behavior: A class that simplifies wireless network procedures.
Behavior names are enclosed in angle brackets < >
. For example, the behavior name for the simple repeater network is <NWK_SIMPLE>
.
Class Object
In this documentation, class objects refer to globally declared objects provided by the library, such as Serial
or Wire
. These class objects can be used immediately or after an initialization procedure.
Class objects that consume a relatively large amount of memory allocate memory during the initialization process according to the provided parameters (via .setup()
or .begin()
methods).
Terminology Related to C++
C++
The C++ programming language.
C++11
A version of the C++ standard. It refers to the C++ standard established in 2011 by ISO. It added significant features compared to the previous C++03 standard. There are newer versions such as C++14 and C++17.
Class
A construct that groups data and procedures related to that data. It is like a structure that also contains procedures to operate on that structure. This is a simplified explanation; please refer to specialized books for deeper understanding.
In C++, the keywords struct
and class
are essentially the same; whichever keyword is used, it defines a class.
struct myhello {
int _i;
void say_hello() { printf("hello %d\n", _i); }
};
If the above class definition were done in C language, it might look like this:
typedef struct _c_myhello {
int _i;
void (*pf_say_hello)(struct _c_myhello *);
} c_myhello;
void say_hello(c_myhello*p) { p->pf_say_hello(); }
void init_c_my_hello(c_myhello*p) {
p->pf_say_hello = say_hello;
}
Wrapper Class
A class that encapsulates existing C language libraries or internal structures, adding C++-specific features to improve usability. In this documentation, you might see descriptions such as “wrapped the ~ structure”.
Method / Member Function
A function defined inside a class and bound to that class.
struct myhello {
int _i;
void say_hello() { printf("hello %d\n", _i); } // Method
};
Object / Instance
An instantiated class (allocated in memory).
void func() {
myhello obj_hello; // obj_hello is an object of class myhello
obj_hello._i = 10;
obj_hello.say_hello();
}
In this documentation, “object” and “instance” are used interchangeably.
Constructor
An initialization procedure called when an object is created.
struct myhello {
int _i;
void say_hello() { printf("hello %d\n", _i); }
myhello(int i = 0) : _i(i) {} // Constructor
};
void my_main() {
myhello helo(10); // Constructor is called here and _i is set to 10
}
Destructor
A procedure paired with the constructor, called when an object is destroyed.
struct myhello {
int _i;
void say_hello() { printf("hello! %d\n", _i); }
myhello(int i = 0) : _i(i) {} // Constructor
~myhello() {
printf("good bye! %d\n", _i);
} // Destructor
};
Abstract Class
In C++, polymorphism is achieved through virtual classes. Specifically, a class with pure virtual functions defined by the virtual
keyword.
struct Base {
virtual void say_hello() = 0;
};
struct DeriveEng : public Base {
void say_hello() { printf("Hello!"); }
};
struct DeriveJpn : public Base {
void say_hello() { printf("Kontiwa!"); }
};
Scope
In C/C++ languages, scope is defined by { }
. Objects created inside this scope are destroyed when exiting the scope, and their destructors are called.
The following example explicitly sets scope. The object helo2
is destroyed and its destructor called when execution reaches line 8.
void my_main() {
myhello helo1(1);
helo1.say_hello();
{
myhello helo2(2);
helo2.say_hello();
}
}
// hello! 1
// hello! 2
// good bye! 2
// good bye! 1
The MWX library uses the following syntax. Here, an object declared inside the condition expression of an if statement (which is not allowed in older C89-style C) is valid only within the {}
block of the if statement.
struct myhello {
int _i;
void say_hello() { printf("hello! %d\n", _i); }
operator bool() { return true; } // Operator for if() condition
myhello(int i = 0) : _i(i) {} // Constructor
~myhello() { printf("good bye! %d\n", _i); } // Destructor
};
// Generator function that creates a myhello object
myhello gen_greeting() { return my_hello(); }
void my_main() {
if (myhello x = gen_greeting()) {
// The myhello object x is valid inside the if block
x.say_hello();
}
// Object x is destroyed when exiting the if block
}
For example, in a dual serial bus, there are procedures for start and end, and the bus is operated by the object only during that time. After the object is created, if the bus connection is appropriate, the true branch of the if statement is executed, and the created object performs bus write or read operations. When the bus read/write operations are finished, the if statement is exited, and the destructor is called, performing the bus release procedure.
const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) { // Initialize bus and check connection
wrt(SHTC3_TRIG_H); // Write
wrt(SHTC3_TRIG_L);
} // Bus release procedure
Namespace
Namespaces are actively used in C++ to avoid name collisions. To access definitions inside a namespace, use the ::
operator.
namespace MY_NAME { // Namespace declaration
const uint8_t MYVAL1 = 0x00;
}
...
void my_main() {
uint8_t i = MY_NAME::MYVAL1; // Reference MY_NAME
}
Template
Templates can be considered an extension of C language macros.
template <typename T, int N>
class myary {
T _buf[N];
public:
myary() : _buf{} {}
T operator [] (int i) { return _buf[i % N]; }
};
myary<int, 10> a1; // Array of 10 integers
myary<char, 128> a2; // Array of 128 chars
This example defines a simple array class. T
and N
are template parameters where T
is a type and N
is a number, defining an array class of N
elements of type T
.
nullptr
In C++11, the null pointer is written as nullptr
. NULL
is a macro representing 0
, but nullptr
often has a distinct entity different from 0
.
Reference Type
C++ supports reference types. Similar to pointers, but with the constraint that they must always refer to an object.
Functions with reference parameters like below can modify the value of i
inside incr()
.
void incr(int& lhs, int rhs) { lhs += rhs; }
void my_main() {
int i = 10; j = 20;
incr(i, j);
}
In this template example, the return type of operator[]
is changed to T&
. This allows direct assignment to internal array data like a[0] = 1
.
template <typename T, int N>
class myary {
T _buf[N];
public:
myary() : _buf{} {}
T& operator [] (int i) { return _buf[i % N]; }
};
myary<int, 10> a1;
void my_main() {
a1[0] = 1;
a1[1] = 2;
}
Type Inference
C++11 introduced the auto
keyword for type inference. The compiler deduces the object type from the initializer, allowing omission of explicit type names. This is effective when template class names become very long.
In this documentation, the universal reference auto&&
is often used. Consider it as a way to write code without worrying about whether the parameter is passed by reference or not.
auto&& p = std::make_pair("HELLO", 5);
// std::pair<const char*, int>
Container
A class that holds multiple objects of a specific data type, such as arrays. The array class myary
shown in the template example is also a container.
smplbuf
and FIFO queue class smplque
.Iterator, .begin()
, .end()
An extension of pointers in C language (pointers can also be used in C++). Pointers in C language are a means to access consecutive memory elements from start to end. Consider a FIFO queue. The simplest implementation is a ring buffer, which does not have contiguous memory. Even so, using iterators allows you to write code similarly to pointer use.
.begin()
and .end()
methods are used to obtain iterators. .begin()
returns an iterator pointing to the container’s first element. .end()
returns an iterator pointing to one past the last element. The reason it points past the last element, not the last itself, is for clarity in loop constructs like for
or while
, and for handling containers with zero elements.
my_queue que; // my_queue is a queue class
auto&& p = que.begin();
auto&& e = que.end();
while(p != e) {
some_process(*p);
++p;
}
Here, for each element in que
, the iterator p
is used to apply some_process()
. The iterator p
is incremented with ++
to point to the next element. Even for containers without contiguous memory, iterators allow pointer-like processing.
Because .end()
points past the last element, the loop termination condition is simply (p != e)
. If the queue is empty, .begin()
equals .end()
(both point to the position where the first element would be inserted).
For containers with contiguous memory, iterators are usually normal pointers, so the overhead is minimal.
C++ Standard Library
The C++ standard library includes the STL (Standard Template Library). The MWX library uses parts of it.
Algorithm
For example, finding the maximum or minimum value was written separately for each type in C language. Such code is often the same except for the type part. C++ uses template
and iterators to write these operations independent of type. This is called algorithms.
// Returns iterator to the maximum element in the range
template <class Iter>
Iter find_max(Iter b, Iter e) {
Iter m = b; ++b;
while(b != e) {
if (*b > *m) { m = b; }
++b;
}
return m;
}
The above is an algorithm to find the maximum value. It is type-independent (generic programming).
#include <algorithm>
auto&& minmax = std::minmax_element( // Get min and max algorithm
que.begin(), que.end());
auto&& min_val = *minmax.first;
auto&& max_val = *minmax.second;
Here, the iterator of que
is passed to std::minmax_element
, an algorithm defined in the C++ standard library. The return value is a std::pair
of two values. The algorithm requires the elements to support <
, >
, and ==
operators for comparison. The return type is deduced from the iterator type.
1.1.1.3 - Design Information
Design Policy
- In application loop code, the goal is to enable code resembling commonly used API structures while adapting implementations to the characteristics of TWELITE.
- TWENET employs event-driven code, which are encapsulated into classes to make this approach manageable. This class-based structure allows application behavior to be encapsulated.
- Event-driven and loop-based code are designed to coexist.
- Representative peripherals are encapsulated into classes to simplify procedures, allowing access through loop-based code where possible.
- Procedures for using boards sold by our company, such as MONOSTICK/PAL, are also encapsulated to streamline usage. (e.g., automating the use of an external watchdog timer)
- Application and board classes incorporate polymorphism to enable uniform procedures. (e.g., to allow loading application classes with different behaviors at startup without rewriting connection code to the TWENET C library)
- All C++ features may be utilized without restriction. For example, the library provides simplified procedures for constructing and parsing complex wireless packets.
- The use of the
->
operator is minimized, and APIs are principally designed to use references.
About the C++ Compiler
Version
gcc version 4.7.4
C++ Language Standard
C++11 (For compiler support status, please refer to publicly available information.)
C++ Limitations
※ These are the known issues as recognized by our team.
- Memory allocation with the
new
andnew[]
operators is possible, but deallocation of the allocated memory is not. Most C++ library features that rely on dynamic memory allocation are effectively unusable. These operators are used only for objects that are created once and never destroyed. - Constructors for global objects are not called.
- Reference: If necessary, you can initialize global objects (including constructor invocation) by calling an initialization function (e.g.,
setup()
) and explicitly initializing likenew ((void*)&obj_global) class_foo();
. - Exceptions (
exception
) cannot be used. - Virtual functions (
virtual
) cannot be used.
Design Notes
This section provides information that will aid your understanding when referencing the MWX library’s code.
Current Implementation
Due to limited development time, certain implementation details may not be fully refined. For example, proper consideration of const
correctness is not adequately implemented across many classes.
Namespace
The following policy is adopted for namespace usage:
- Definitions are, in principle, placed under the common namespace
mwx
. - While the goal is to allow usage without explicitly specifying the namespace, some definitions require explicit identifiers.
- Class names are generally long, and user-facing names are provided via alias definitions.
Classes, functions, and constants are defined within the mwx
namespace (more precisely, within inline namespace L1
inside mwx::L1
), with inline namespace
used to allow coexistence of definitions that require the mwx::
prefix and those that do not.
Most definitions are made accessible without needing to specify the namespace, via using namespace
directives in using_mwx_def.hpp
.
// at some header file.
namespace mwx {
inline namespace L1 {
class foobar {
// class definition...
};
}
}
// at using_mwx_def.hpp
using namespace mwx::L1; // Definitions in mwx::L1 are accessible without mwx::
// But mwx::L2 still requires mwx:: prefix.
Shorter names such as mwx::crlf
, mwx::flush
are explicitly defined within mwx::L2
, and can be accessed without a namespace prefix by including using namespace mwx::L2;
.
Additionally, some class names are made available via using
declarations.
The std::make_pair
used within the MWX library is also made available via using
.
CRTP (Curiously Recurring Template Pattern)
Because virtual functions (virtual
) and runtime type information (RTTI) are not available—or even if they were, would incur significant performance penalties—MWX uses the CRTP (Curiously Recurring Template Pattern) as an alternative design technique. CRTP is a template pattern that enables calling methods of a derived class from its base class.
The following example demonstrates implementing an interface()
in a Derived
class that inherits from Base
. The Base
class calls the Derived::prt()
method.
template <class T>
class Base {
public:
void intrface() {
T* derived = static_cast<T*>(this);
derived->prt();
}
};
class Derived : public Base<Derived> {
void prt() {
// print message here!
my_print("foo");
}
};
The main classes in the MWX library that utilize CRTP are:
- Core event processing:
mwx::appdefs_crtp
- State machine:
public mwx::processev_crtp
- Stream:
mwx::stream
Virtualization with CRTP
With CRTP, each derived class has a different base class instantiation. This means you cannot treat them as the same type by casting to the parent class, nor can you use advanced polymorphism techniques such as virtual functions (virtual
) or RTTI.
Below is an example of how you would implement the same pattern using virtual functions. With CRTP, you cannot directly manage instances in the same array like Base* b[2]
.
class Base {
virtual void prt() = 0;
public:
void intrface() { prt(); }
};
class Derived1 : public Base {
void prt() { my_print("foo"); }
};
class Derived2 : public Base {
void prt() { my_print("bar"); }
};
Derived1 d1;
Derived2 d2;
Base* b[2] = { &d1, &d2 };
void tst() {
for (auto&& x : b) { x->intrface(); }
}
In the MWX library, this limitation is addressed by defining a dedicated container class for CRTP-based instances, which provides a common interface. The following example illustrates this approach:
class VBase {
public:
void* p_inst;
void (*pf_intrface)(void* p);
public:
void intrface() {
if (p_inst != nullptr) {
pf_intrface(p_inst);
}
}
};
template <class T>
class Base {
friend class VBase;
static void s_intrface(void* p) {
T* derived = static_cast<T*>(p);
derived->intrface();
}
public:
void intrface() {
T* derived = static_cast<T*>(this);
derived->prt();
}
};
class Derived1 : public Base<Derived1> {
friend class Base<Derived1>;
void prt() { my_print("foo"); }
};
class Derived2 : public Base<Derived2> {
friend class Base<Derived2>;
void prt() { my_print("bar"); }
};
Derived1 d1;
Derived2 d2;
VBase b[2];
void tst() {
b[0] = d1;
b[1] = d2;
for (auto&& x : b) {
x.intrface();
}
}
The VBase
class contains a pointer p_inst
to a Base<T>
object and a function pointer pf_intrface
to the corresponding static interface function (Base<T>::s_intrface
). Base<T>::s_intrface
receives the object instance as a parameter, casts it to the appropriate type, and calls T::intrface()
.
Assignment to VBase
is implemented via an overloaded =
operator (see the next code example).
When calling b[0].intrface()
, the function pointer VBase::pf_intrface
is invoked, which calls Base<Derived1>::s_intrface()
, which in turn calls Derived1::intrface()
. This call chain is expected to be inlined by the compiler.
It is also possible to cast from VBase
back to the original Derived1
or Derived2
type, but since the pointer is stored as void*
, the actual type cannot be determined safely at runtime. To mitigate this, a unique type ID (TYPE_ID
) is assigned to each class, and the get()
method checks the ID before casting. If a mismatched type is requested, an error is reported.
Additionally, when storing a pointer as Base<T>
, there is a possibility that it cannot be safely cast back to T
(for example, with multiple inheritance). Therefore, a compile-time check using static_assert
and <type_traits>::is_base_of
ensures that T
is indeed derived from Base<T>
.
// Note: <type_trails> should be <type_traits>
#include <type_traits>
class Derived1 : public Base<Derived1> {
public:
static const uint8_t TYPE_ID = 1;
};
class Derived2 : public Base<Derived2> {
public:
static const uint8_t TYPE_ID = 2;
};
class VBase {
uint8_t type_id;
public:
template <class T>
void operator = (T& t) {
static_assert(std::is_base_of<Base<T>, T>::value == true,
"is not base of Base<T>.");
type_id = T::TYPE_ID;
p_inst = &t;
pf_intrface = T::s_intrface;
}
template <class T>
T& get() {
static_assert(std::is_base_of<Base<T>, T>::value == true,
"is not base of Base<T>.");
if(T::TYPE_ID == type_id) {
return *reinterpret_cast<T*>(p_inst);
} else {
// panic code here!
}
}
};
Derived1 d1;
Derived2 d2;
VBase b[2];
void tst() {
b[0] = d1;
b[1] = d2;
Derived1 e1 = b[0].get<Derived1>(); // OK
Derived2 e2 = b[1].get<Derived2>(); // OK
Derived2 e3 = b[1].get<Derived1>(); // PANIC!
}
new and new[] Operators
TWELITE modules do not have abundant memory or advanced memory management. However, the area from the end of the application RAM to the start of the stack is available as a heap, from which memory can be allocated as needed. The following diagram shows the memory map: APP is the RAM area allocated for application code, HEAP is the heap, and STACK is the stack.
|====APP====:==HEAP==.. :==STACK==|
0 32KB
Even though delete
is not supported, there are cases where the new
operator is still useful. Therefore, the new
and new[]
operators are defined as follows. pvHeap_Alloc()
is a memory allocation function provided by the semiconductor library, and u32HeapStart
, u32HeapEnd
mark the heap boundaries. 0xdeadbeef
is used as a dummy address.
Please refrain from comments about “beef” being “dead”.
void* operator new(size_t size) noexcept {
if (u32HeapStart + size > u32HeapEnd) {
return (void*)0xdeadbeef;
} else {
void *blk = pvHeap_Alloc(NULL, size, 0);
return blk;
}
}
void* operator new[](size_t size) noexcept {
return operator new(size); }
void operator delete(void* ptr) noexcept {}
void operator delete[](void* ptr) noexcept {}
Because exceptions are not supported, there is no handling for allocation failure. Also, if you continue allocating memory without regard for capacity, you may collide with the stack area.
Container Classes
In the MWX library, considering the limited resources of microcontrollers and the inability to perform dynamic memory allocation, the standard library’s container classes are not used. Instead, two simple container classes are defined. These container classes provide iterators and begin()
, end()
methods, allowing the use of range-based for
loops and some STL algorithms.
smplbuf<int16_t, alloc_local<int16_t, 16>> buf;
buf.push_back(-1); // push_back() adds to the end
buf.push_back(2);
...
buf.push_back(10);
// Range-based for loop
for(auto&& x : buf) { Serial << int(x) << ','; }
// STL algorithm: std::minmax
auto&& minmax = std::minmax_element(buf.begin(), buf.end());
Serial << "Min=" << int(*minmax.first)
<< ",Max=" << int(*minmax.second);
Class Name | Description |
---|---|
smplbuf | An array class that manages the maximum capacity and usable size (within the maximum capacity) dynamically. This class also implements a stream interface, so you can write data using the << operator. |
smplque | Implements a FIFO queue. The queue size is determined by a template parameter. There is also a template argument for operating the queue with interrupt disabling. |
Memory Management for Container Classes
For container classes, the memory allocation method is specified as a template parameter.
Class Name | Description |
---|---|
alloc_attach | Specifies an already allocated buffer memory. Use this when you want to manage a memory region allocated for a C library, or when you want to treat a subdivided region of the same buffer. |
alloc_static | Allocates as a static array within the class. Use when the size is known in advance or for temporary use. |
alloc_heap | Allocates in the heap area. Once allocated in the system heap, it cannot be released, but this is suitable for allocating memory according to application settings at initialization. |
Variadic Templates
In the MWX library, variadic templates are used for operations involving byte and bit sequences, or for procedures equivalent to printf
. The following example shows a function that sets bits at specified positions.
// packing bits with given arguments, which specifies bit position.
// pack_bits(5, 0, 1) -> (b100011) bit0,1,5 are set.
// Base case for recursion
template <typename Head>
constexpr uint32_t pack_bits(Head head) { return 1UL << head; }
// Recursive unpacking: takes the head and passes the tail recursively
template <typename Head, typename... Tail>
constexpr uint32_t pack_bits(Head head, Tail&&... tail) {
return (1UL << head) | pack_bits(std::forward<Tail>(tail)...);
}
// After compilation, the following two will result in the same value.
constexpr uint32_t b1 = pack_bits(1, 4, 0, 8);
// b1 and b2 are the same!
const uint32_t b2 = (1UL << 1)|(1UL << 4)|(1UL << 0)|(1UL << 8);
This procedure uses a parameter pack (typename...
) in a template to recursively expand the arguments. Because constexpr
is specified in the above example, the computation is performed at compile time and yields the same result as a macro or a const
value such as b2
. It can also act as a function that dynamically calculates values at runtime.
In the next example, the expand_bytes
function stores values from the received packet’s payload into local variables. Since parameter packs allow you to deduce each argument’s type, it becomes possible to safely extract values of appropriate sizes and types from the byte stream.
auto&& rx = the_twelite.receiver.read(); // received packet
// Variables to hold the expanded packet contents
// The packet payload contains bytes arranged as follows:
// [B0][B1][B2][B3][B4][B5][B6][B7][B8][B9][Ba][Bb]
// <message ><adc* ><vcc* ><timestamp* >
// * Numeric types are in big endian order
uint8_t msg[MSG_LEN];
uint16_t adcval, volt;
uint32_t timestamp;
// Expand packet payload
expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, msg // 4 bytes of message
, adcval // 2 bytes, A1 value [0..1023]
, volt // 2 bytes, module VCC [mV]
, timestamp // 4 bytes of timestamp
);
Iterators
Iterators serve as an abstraction over pointers, allowing access to data structures as if you were using pointers—even for structures where memory is not contiguous.
In the C++ STL, it is common to use the iterator returned by the begin()
method (pointing to the start of the container) together with the iterator from end()
(pointing just past the last element).
smplque<uint8_t, alloc_local<uint8_t, 5> > que;
que.push('a'); que.push('b'); que.pop(); que.push('c'); ...
auto&& p = que.begin();
auto&& e = que.end();
while (p != e) { // When p reaches e, all elements have been processed
Serial << *p;
++p; // Use the pre-increment operator for iterator increment.
// While using p++ may be optimized by the compiler,
// it involves making a copy of the iterator in code.
}
By conforming iterators to the standard library specification, you can use range-based for
loops and standard library algorithms.
#include <algorithm>
#include <cctype>
// Character conversion using a lambda expression
std::for_each(que.begin(), que.end(),
[](uint8_t& x) { x = std::toupper(x); });
// Range-based for loop
for (uint8_t x : que) {
Serial << x;
}
(The MWX library does not guarantee full compatibility or conformance with the C++ standard library. Please verify operation before use.)
The following example demonstrates using iterators for a FIFO queue, where contiguous access with a normal pointer is not possible. It also shows how to use an iterator that extracts only a specific member (the X axis in this example) from a structure stored in the queue.
// A queue of 5 elements, each of which is a 4-axis XYZT structure
smplque<axis_xyzt, alloc_local<axis_xyzt, 5> > que;
// Insert test data
que.push(axis_xyzt(1, 2, 3, 4));
que.push(axis_xyzt(5, 2, 3, 4));
...
// Access using an iterator over the structure
for (auto&& e : v) { Serial << int(e.x) << ','; }
// Extract the X axis from the queue
auto&& vx = get_axis_x(que);
// Access using an iterator over the X axis
for (auto&& e : vx) { Serial << int(e) << ','; }
// Since the iterator yields int16_t elements, you can use STL algorithms (min/max)
auto&& minmax = std::minmax_element(vx.begin(), vx.end());
Below is an excerpt from the implementation of the iterator for the smplque
class. This iterator manages the underlying queue object and the index. The fact that the queue’s memory is not contiguous (due to the ring buffer structure, where the end wraps to the beginning) is handled by smplque::operator[]
. Two iterators are considered equal if both the object addresses and the indices are equal.
This implementation also includes the typedef
s required by <iterator>
, enabling more STL algorithms to be used.
class iter_smplque {
typedef smplque<T, alloc, INTCTL> BODY;
private:
uint16_t _pos; // index
BODY* _body; // pointer to the original object
public: // for <iterator>
typedef iter_smplque self_type;
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
public: // selected methods
inline reference operator *() {
return (*_body)[_pos];
}
inline self_type& operator ++() {
_pos++;
return *this;
}
};
Iterators that access only a specific member of a structure stored in a container are somewhat more complex. First, define member functions to access each member. Then, define a template that takes such a member function as a parameter (R& (T::*get)()
). Here, Iter
is the iterator type of the container class.
struct axis_xyzt {
int16_t x, y, z;
uint16_t t;
int16_t& get_x() { return x; }
int16_t& get_y() { return y; }
int16_t& get_z() { return z; }
};
template <class Iter, typename T, typename R, R& (T::*get)()>
class _iter_axis_xyzt {
Iter _p;
public:
inline self_type& operator ++() {
_p++;
return *this;
}
inline reference operator *() {
return (*_p.*get)();
}
};
template <class Ixyz, class Cnt>
class _axis_xyzt_iter_gen {
Cnt& _c;
public:
_axis_xyzt_iter_gen(Cnt& c) : _c(c) {}
Ixyz begin() { return Ixyz(_c.begin()); }
Ixyz end() { return Ixyz(_c.end()); }
};
// Use a type alias to shorten the (long) type
template <typename T, int16_t& (axis_xyzt::*get)()>
using _axis_xyzt_axis_ret = _axis_xyzt_iter_gen<
_iter_axis_xyzt<typename T::iterator, axis_xyzt, int16_t, get>, T>;
// Generator for extracting the X axis
template <typename T>
_axis_xyzt_axis_ret<T, &axis_xyzt::get_x>
get_axis_x(T& c) {
return _axis_xyzt_axis_ret<T, &axis_xyzt::get_x>(c);
}
The operator*
for value access invokes the above member function. (*_p
is an axis_xyzt
structure, so (*_p.*get)()
calls, for example, _p->get_x()
if T::*get
is &axis_xyzt::get_x
.)
The _axis_xyzt_iter_gen
class implements only begin()
and end()
, and generates the above iterator. This enables the use of range-based for
and STL algorithms.
Because the type names are long and unwieldy in source code, a generator function is provided for convenience. In the example above, this is the get_axis_x()
function at the end. Using this generator function allows concise code such as auto&& vx = get_axis_x(que);
as shown at the start of this section.
This axis-extracting iterator can also be used with the array-type smplbuf
class in the same way.
Implementing Interrupt, Event, and State Handlers
To describe application behavior via user-defined classes, it is necessary to define certain representative handlers as required methods. However, defining all the possible interrupt handlers, event handlers, and state handlers for the state machine can be tedious, as there are many of them. Ideally, only the handlers defined by the user should be instantiated, and only those should have code executed.
class my_app_def {
public: // Definition of required methods
void network_event(twe::packet_ev_nwk& pEvNwk) {}
void receive(twe::packet_rx& rx) {}
void transmit_complete(twe::packet_ev_tx& pEvTx) {}
void loop() {}
void on_sleep(uint32_t& val) {}
void warmboot(uint32_t& val) {}
void wakeup(uint32_t& val) {}
public: // Making all of these mandatory would be cumbersome
// 20 DIO interrupt handlers
// 20 DIO event handlers
// 5 timer interrupt handlers
// 5 timer event handlers
// ...
};
In the MWX library, for handlers with large numbers (such as DIO interrupt handlers—on TWELITE hardware, there is only a single interrupt, but for usability, a handler is assigned to each DIO pin), we define empty handler templates. The user can then specialize only the handlers they need by specializing these templates with their own member functions.
// hpp file
class my_app_def : class app_defs<my_app_def>, ... {
// Empty handler template
template<int N> void int_dio_handler(uint32_t arg, uint8_t& handled) { ; }
...
// Only implement for number 12
public:
// Callback function called from TWENET
uint8 cbTweNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap);
};
// cpp file
template <>
void my_app_def::int_dio_handler<12>(uint32_t arg, uint8_t& handled) {
digitalWrite(5, LOW);
handled = true;
return;
}
void cbTweNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap) {
uint8_t b_handled = FALSE;
switch(u32DeviceId) {
case E_AHI_DEVICE_SYSCTRL:
if (u32ItemBitmap & (1UL << 0)){int_dio_handler<0>(0, b_handled);}
if (u32ItemBitmap & (1UL << 1)){int_dio_handler<1>(1, b_handled);}
...
if (u32ItemBitmap & (1UL << 12)){int_dio_handler<12>(12, b_handled);}
...
if (u32ItemBitmap & (1UL << 19)){int_dio_handler<19>(19, b_handled);}
break;
}
}
In actual user code, macros and header file includes can simplify the code, but the above shows the necessary code for explanation.
The interrupt handler from TWENET will call my_app_def::cbTweNet_u8HwInt()
. In the .cpp
file, only int_dio_handler<12>
is specialized and instantiated with the user-defined content; for all other numbers, the template from the .hpp
file is instantiated. As a result, the code expands as follows:
case E_AHI_DEVICE_SYSCTRL:
if (u32ItemBitmap & (1UL << 0)){;}
if (u32ItemBitmap & (1UL << 1)){;}
...
if (u32ItemBitmap & (1UL << 12)){
int_dio_handler<12>(12, b_handled);}
...
if (u32ItemBitmap & (1UL << 19)){;}
break;
// ↓ ↓ ↓
// After optimization, the code is expected to look like this:
case E_AHI_DEVICE_SYSCTRL:
if (u32ItemBitmap & (1UL << 12)){
// int_dio_handler<12> is also inlined
digitalWrite(5, LOW);
handled = true;
}
break;
Ultimately, it is expected that the compiler’s optimization will recognize the code for all but number 12 as unnecessary and eliminate it from the binary (though this optimization cannot be guaranteed).
In other words, if you want to define the behavior for interrupt number 12 in your user code, it is sufficient to implement int_dio_handler<12>
. (Note: To enable DIO interrupts, you must call attachInterrupt()
.) Handlers that are not registered are expected to result in minimal overhead due to compile-time optimization.
There is also a linker-level technique to enable a function if defined by the user, or call a different function if not. This can be done by specifying __attribute__((weak))
as shown below. If the user code defines a wakeup()
function, the user’s function will be linked; if not, an empty function is linked instead.
// mwx_appcore.cpp
void wakeup() __attribute__((weak));
void wakeup() { }
For the implementation of the above handlers, it is necessary to explicitly generate a weak-specified member variable, and it is difficult to optimize with inline expansion, so this method is not used for interrupt handlers. However, for some callback functions from TWENET such as wakeup()
, a weak-specified function is defined as a fallback.
Stream Class
The stream class is primarily used for UART (serial port) input and output. In the MWX library, output procedures are mainly defined, with some input definitions also available.
This section explains the implementation required by derived classes.
template <class D>
class stream {
protected:
void* pvOutputContext; // TWE_tsFILE*
public:
inline D* get_Derived() { return static_cast<D*>(this); }
inline D& operator << (char c) {
get_Derived()->write(c);
return *get_Derived();
}
};
class serial_jen : public mwx::stream<serial_jen> {
public:
inline size_t write(int n) {
return (int)SERIAL_bTxChar(_serdef._u8Port, n);
}
};
The above shows the implementation of the write()
method for writing a single character. The base class stream<serial_jen>
uses the get_Derived()
method to cast itself to serial_jen
and access the serial_jen::write()
method.
As needed, you can define methods such as write()
, read()
, flush()
, and available()
.
For formatted output, the library uses Marco Paland’s printf library. To use this from the MWX library, you need to implement the appropriate interface. In the following example, the derived class serial_jen
must define a vOutput()
method for single-byte output, and since vOutput()
is a static method, the base class stores auxiliary information for output in pvOutputContext
.
template <class D>
class stream {
protected:
void* pvOutputContext; // TWE_tsFILE*
public:
inline tfcOutput get_pfcOutout() { return get_Derived()->vOutput; }
inline D& operator << (int i) {
(size_t)fctprintf(get_pfcOutout(), pvOutputContext, "%d", i);
return *get_Derived();
}
};
class serial_jen : public mwx::stream<serial_jen> {
using SUPER = mwx::stream<serial_jen>;
TWE_tsFILE* _psSer; // Low-level structure for serial output
public:
void begin() {
SUPER::pvOutputContext = (void*)_psSer;
}
static void vOutput(char out, void* vp) {
TWE_tsFILE* fp = (TWE_tsFILE*)vp;
fp->fp_putc(out, fp);
}
};
By using get_pfcOutout()
, the function pointer to the derived class’s vOutput()
is specified, with pvOutputContext
passed as its parameter. In the above example, when the <<
operator is called with an int
, serial_jen::vOutput()
and the UART-configured TWE_tsFILE*
are passed to the fctprintf()
function.
Worker Objects for Wire and SPI
For the Wire
class, which handles I2C communication, it is necessary to manage communication from start to finish when transmitting or receiving to/from two-wire devices. The following describes usage with worker objects.
if (auto&& wrt = Wire.get_writer(SHTC3_ADDRESS)) {
Serial << "{I2C SHTC3 connected.";
wrt << SHTC3_TRIG_H;
wrt << SHTC3_TRIG_L;
Serial << " end}";
}
Below is an excerpt from the periph_twowire::writer
class. To implement the stream interface, it inherits from mwx::stream<writer>
. The write()
and vOutput()
methods are implemented to support the stream interface.
The constructor initiates I2C communication, and the destructor finalizes it. The operator bool()
returns true
if communication with the I2C device was successfully started.
class periph_twowire {
public:
class writer : public mwx::stream<writer> {
friend class mwx::stream<writer>;
periph_twowire& _wire;
public:
writer(periph_twowire& ref, uint8_t devid) : _wire(ref) {
_wire.beginTransmission(devid); // Start communication in constructor
}
~writer() {
_wire.endTransmission(); // End communication in destructor
}
operator bool() {
return (_wire._mode == periph_twowire::MODE_TX);
}
private: // stream interface
inline size_t write(int n) {
return _wire.write(val);
}
// for upper class use
static void vOutput(char out, void* vp) {
periph_twowire* p_wire = (periph_twowire*)vp;
if (p_wire != nullptr) {
p_wire->write(uint8_t(out));
}
}
};
public:
writer get_writer(uint8_t address) {
return writer(*this, address);
}
};
class periphe_twowire Wire; // global instance
// User code
if (auto&& wrt = Wire.get_writer(SHTC3_ADDRESS)) {
Serial << "{I2C SHTC3 connected.";
wrt << SHTC3_TRIG_H;
wrt << SHTC3_TRIG_L;
Serial << " end}";
}
The get_writer()
method creates the wrt
object. Normally, object copying does not occur here. Due to C++’s Return Value Optimization (RVO), the writer
is constructed directly in wrt
without copying, so bus initialization performed in the constructor is not repeated. However, since RVO is not strictly guaranteed by the C++ standard, the MWX library explicitly deletes copy/move assignment operators and defines a move constructor (even though the move constructor is not expected to be invoked).
Within the if
block, wrt
is initialized by the constructor, which also starts communication. If communication is successfully started, the operator bool()
returns true
, and the block is executed. Upon leaving the scope, the destructor finalizes the use of the I2C bus. If the target device is not present, operator bool()
returns false
and the wrt
object is destroyed.
For Wire
and SPI
in particular, the default behavior of the operator << (int)
is overridden. The default stream behavior converts numbers to strings before output, but with Wire
and SPI
, it is rare to write numeric strings to the bus. More often, you want to send literal numeric values directly (such as configuration values), but numeric literals are typically evaluated as int
. Therefore, this behavior is changed.
writer& operator << (int v) {
_wire.write(uint8_t(v & 0xFF));
return *this;
}
Here, values of type int
are truncated to 8 bits and output directly.
1.1.2 - Definitions
This section cites the definition contents that are commonly included throughout the library.
mwx_common.h
##include <cstdint> // for type name
typedef char char_t;
typedef uint8_t byte;
typedef uint8_t boolean;
##ifndef NULL
##define NULL nullptr
##endif
1.1.3 - Class Objects
Class objects are predefined in the MWX library, including the_twelite
for handling TWENET and objects for using peripherals.
Each object must be initialized by calling its .setup()
and .begin()
methods.
(Only the Serial
object that uses UART0
does not require initialization.)
1.1.3.1 - the_twelite
the_twelite
object consolidates procedures for using TWENET, including basic wireless settings, sleep procedures, and other operations to control the wireless microcontroller.Overview
the_twelite
performs settings and start the_twelite.begin()
within the setup()
function. Settings cannot be done outside of setup()
.
void setup() {
...
the_twelite
<< TWENET::appid(APP_ID)
<< TWENET::channel(CHANNEL)
<< TWENET::rx_when_idle();
...
the_twelite.begin();
}
In the above example, the application ID setting, communication channel setting, and receiver circuit setting are performed.
Various procedures are included.
// Get the serial number
uint32_t u32hwser = the_twelite.get_hw_serial();
// Set channel to 11
the_twelite.change_channel(11);
// Sleep for 1 second
the_twelite.sleep(1000);
// Perform reset
the_twelite.reset_system();
Also, classes that handle wireless networks, board support, and user-written event-driven processing can be registered. By registering these classes, specialized functions can be easily utilized. These classes are referred to as “Behaviors” in this documentation.
void setup() {
/*** SETUP section */
// use PAL_AMB board support.
auto&& brd = the_twelite.board.use<PAL_AMB>();
...
// Register Network
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << NWK_SIMPLE::logical_id(u8ID);
In the above example, two types are registered: the environmental sensor PAL <PAL_AMB>
and the simple relay network <NWK_SIMPLE>
. By registering these, hardware such as sensors on the environmental sensor PAL can be easily handled. Also, complicated wireless packet handling such as relay processing and automatic discarding of duplicate packets can be implicitly enabled.
Methods
The MWX library defines methods other than those introduced here.
These include methods unrelated to actor description, those that do not function effectively even if set, and those used internally.
<<
operator (Settings)
The <<
operator is used to perform initial settings of the the_twelite
object.
The following setting class objects are input, and if not set, default values are applied.
TWENET::appid(uint32_t id)
Sets the application ID specified by parameter id
. This is mandatory.
Reading the setting is done by uint32_t the_twelite.get_appid()
.
TWENET::channel(uint8_t ch)
Sets the channel number (11
..26
) specified by parameter ch
.
Reading the setting is done by uint8_t the_twelite.get_channel()
.
TWENET::tx_power(uint8_t pw)
Sets the output power setting (0
..3
) specified by parameter pw
. The default is (3: no output attenuation).
Reading the setting is done by uint8_t the_twelite.get_tx_power()
.
TWENET::rx_when_idle(uint8_t bEnable)
If parameter bEnable
is 1
, the receiver circuit is always active to receive wireless packets from others. The default is 0
, meaning mainly transmission only.
Reading the setting is done by uint8_t the_twelite.get_rx_when_idle()
.
TWENET::chmgr(uint8_t ch1 = 18, uint8_t ch2 = 0, uint8_t ch3 = 0)
Enables the channel manager. If multiple channels are specified, transmission and reception are performed on multiple channels. If 0
is specified for ch2
or ch3
, that specification is disabled.
STG_STD
Applies the Interactive Mode settings.
auto&& set = the_twelite.settings.use<STG_STD>();
...
set.reload(); // Load settings
the_twelite << set; // Apply Interactive Mode settings
The applied items are as follows:
app_id
channel
tx_power
- Retransmission count when using MAC ack
begin()
void begin()
Execute after completing prior settings (<<
operator reference) and behavior registration. Usually placed at the very end of the setup()
function.
the_twelite
setup completed- Behavior initialization
setup()
function finishes. Since many processes are designed to run after setup()
ends, avoid performing anything other than initialization here.Example
void setup() {
// use PAL_AMB board support.
auto&& brd = the_twelite.board.use<PAL_AMB>();
// settings
the_twelite
<< TWENET::appid(APP_ID)
<< TWENET::channel(CHANNEL)
<< TWENET::rx_when_idle();
// Register Network
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << NWK_SIMPLE::logical_id(u8ID);
// some others
// begin the TWENET!
the_twelite.begin();
}
change_channel()
inline bool change_channel(uint8_t u8Channel)
Changes the channel setting. If it fails, the channel is not changed and returns false
.
get_channel_phys()
uint8_t get_channel_phys()
Gets the currently set channel number (11..26). Obtained from the MAC layer API.
get_hw_serial()
inline uint32_t get_hw_serial()
Gets the module’s serial number.
sleep()
inline void sleep(
uint32_t u32Periodms,
bool_t bPeriodic = true,
bool_t bRamOff = false,
uint8_t u8Device = TWENET::SLEEP_WAKETIMER_PRIMARY)
Puts the module to sleep.
Parameter | Description |
---|---|
u32Periodms | Sleep duration [ms] |
bPeriodic | Recalculates next wake-up time based on the last wake-up time. ※ Sometimes the next wake-up timing may be from the current time due to proximity. |
bRamoff | If set to true , sleep without retaining RAM (after waking up, reinitialization should start from setup() instead of wakeup() ) |
u8Device | Specifies the wake-up timer used for sleep. Specify either TWENET::SLEEP_WAKETIMER_PRIMARY or TWENET::SLEEP_WAKETIMER_SECONDARY . |
on_sleep()
method of embedded objects and behaviors is called to perform pre-sleep procedures. After wake-up, the on_wakeup()
method is called for recovery processing.is_wokeup_by_dio()
bool is_wokeup_by_dio(uint8_t port)
Returns true
if the wake-up cause from sleep is the specified digital pin.
is_wokeup_by_wktimer()
bool is_wokeup_by_wktimer()
Returns true
if the wake-up cause from sleep is the wake-up timer.
reset_system()
inline void reset_system()
Resets the system. After reset, processing starts from setup()
.
stop_watchdog()
inline void stop_watchdog()
Stops the watchdog timer. Stop the timer when performing long polling waits.
restart_watchdog()
inline void restart_watchdog()
Restarts the watchdog timer.
Behaviors
twe_twelite
can register three behaviors, and the following class objects are defined to hold them.
network
: Behavior implementing the network. Usually register<NWK_SIMPLE>
.network2
: Behavior implementing the network. Used when you want to process packets rejected bynetwork
(due to payload data structure or other criteria) with another network behavior. (Reference: Using NWK_LAYERED and NWK_SIMPLE together)board
: Behavior for board support. Adds procedures for using devices on the board.app
: Behavior describing user applications. Allows writing interrupt or event descriptions and state transitions using state machines. Also allows defining multiple application descriptions and easily selecting completely different applications at startup.settings
: Behavior for executing settings (Interactive Mode). Register<SET_STD>
.
use<B>()
// Example
auto&& brd = the_twelite.board.use<PAL_AMB>();
Registers behavior <B>
. Registration is done inside setup()
. The return value is a reference to the object corresponding to the registered behavior.
After registration, the object can be retrieved with the same syntax as during registration.
Declaring behavior objects as global variables is not intended. Use use<B>()
each time you use it.
void loop() {
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
}
However, it is possible to define a pointer to the object as a global variable and write as follows. (In MWX library, pointer types are minimized and references are preferred, so such usage is not recommended.)
NWK_SIMPLE *pNwk = nullptr;
setup() {
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
pNwk = &nwk;
}
void transmit() {
if (auto&& pkt = pNwk->prepare_tx_packet()) {
...
}
}
Class Objects
the_twelite
defines the three class objects board
, network
, and app
mentioned above, and also defines the following.
tx_status
Notifies the transmission completion status.
transmit_complete()
callback.is_complete()
bool is_complete(uint8_t cbid)
Returns true
when the packet with the specified ID has completed transmission.
is_success()
bool is_success(uint8_t cbid)
Returns true
when the packet with the specified ID has completed transmission and the transmission was successful.
receiver
Obtains received packets.
the_twelite.receiver
is not recommended.
Previously, processing using the_twelite.receiver
was intended inside loop()
, but due to delay processing by queue, packet loss can occur in principle, and the description tends to be complicated. Therefore, on_rx_packet()
was added.
- In event-driven behavior descriptions, obtain via
receive()
callback.
read()
method is designed to be overwritten by subsequent packets during reception processing. If you read immediately after available
and perform short processing, it is not a problem, but in principle, read → copy necessary data for application → quickly finish loop()
. For example, performing long delay()
in loop()
may cause packet loss.available()
bool available()
Returns true
if there is a received packet not yet read.
read()
packet_rx& read()
Reads a packet.
1.1.3.2 - Analogue
Constants
Pin Definitions
Constant | Type | Standard App Pin Name |
---|---|---|
uint8_t PIN_ANALOGUE::A1 = 0 | ADC1 Pin | AI1 |
uint8_t PIN_ANALOGUE::A2 = 1 | ADC2 Pin | AI3 |
uint8_t PIN_ANALOGUE::A3 = 2``uint8_t PIN_ANALOGUE::D0 = 2 | ADC3 Pin (DIO0) *1 | AI2 |
uint8_t PIN_ANALOGUE::A4 = 3``uint8_t PIN_ANALOGUE::D1 = 3 | ADC4 Pin (DIO1) *1 | AI4 |
uint8_t PIN_ANALOGUE::VCC = 4 | Vcc Power Supply Voltage |
*1 The ADC2/ADC3 pins shared by digital and analog have usage procedures and restrictions.
Before starting ADC, set the pins to be used to no pull-up. If this is not done, the ADC will always observe the pull-up voltage.
pinMode(PIN_DIGITAL::DIO0, PIN_MODE::INPUT);
pinMode(PIN_DIGITAL::DIO1, PIN_MODE::INPUT);
In a normal circuit configuration, current leakage occurs during sleep. This cannot be avoided by software alone.
To avoid current leakage during sleep, disconnect the GND of the analog circuit part with a FET switch or similar, leaving it floating during sleep. Also, before sleep, set the pins to input with pull-up enabled.
Methods
setup()
void setup(
bool bWaitInit = false,
uint8_t kick_ev = E_AHI_DEVICE_TICK_TIMER,
void (*fp_on_finish)() = nullptr)
Initializes the ADC. In setup(), it starts the internal semiconductor regulator, specifies the timer device for periodic execution, and specifies a callback function called when all specified ADC channels have finished.
Parameter | Description |
---|---|
bWaitInit | If true , waits for the internal semiconductor regulator initialization. |
kick_ev | Specifies the timer device for periodic execution. The following five devices can be specified. Except for the first time, ADC starts in the interrupt handler. E_AHI_DEVICE_TICK_TIMER (TickTimer)``E_AHI_DEVICE_TIMER0 .. 4 (Timer0 .. 4) |
fp_on_finish | Callback function called from the interrupt handler after all specified ports’ ADCs finish. Useful for separately storing ADC measurement values in FIFO queues, etc. |
begin()
void begin(uint8_t bmPorts, uint8_t capt_tick = 1)
The first parameter specifies the ports for ADC. The port specification is a bitmap with bits set corresponding to the port numbers defined in the pin definitions. For example, to get values of PIN_ANALOGUE::A2
and PIN_ANALOGUE::VCC
, specify (1 <<PIN_ANALOGUE::A1 | 1<<PIN_ANALOGUE::VCC )
. You can also write pack_bits(PIN_ANALOGUE::A1,PIN_ANALOGUE::VCC)
using pack_bits
.
After calling begin()
, the first ADC process starts promptly, and after its completion interrupt, the next pin process starts. When all processes finish, the callback function (if specified) is called. The next ADC process starts after waiting for the next timer interrupt.
The second parameter specifies the number of timer interrupts before starting ADC. For example, TickTimer
is called every 1ms, and specifying 16
means processing every 16ms.
void begin()
Starts ADC processing with default ADC pins (PIN_ANALOGUE::A1
,PIN_ANALOGUE::A2
). end()
resumes interrupted ADC processing.
end()
void end()
Stops ADC processing and stops the internal semiconductor regulator.
available()
inline bool available()
Returns true
after ADC values are obtained. After checking with this function, it returns false
until the next ADC completion.
read()
, read_raw()
inline int16_t read(uint8_t s)
inline int16_t read_raw(uint8_t s)
Reads ADC values. The parameter specifies the ADC pin to read. read()
returns the value converted to mV, and read_raw()
returns the ADC value (0..1023).
read()
. To convert the read_raw()
value to mV, a special conversion formula must be applied.loop()
processing.ADC Interrupt Handler
The ADC interrupt handler is set to periph_analogue::ADC_handler()
when setup()
is called.
Specifying a handler separately in the semiconductor peripheral library will cause malfunction.
Behavior During Sleep
If ADC is in periodic execution state by begin()
, ADC processing resumes after wake-up from sleep.
Since setup(true)
is automatically called on wake-up from sleep, when using timers other than E_AHI_DEVICE_TICK_TIMER
, explicitly reinitialize in wakeup()
.
For example, inserting the following code reinitializes with E_AHI_DEVICE_TIMER0
on wake-up.
void wakeup()
{
Analogue.setup(true, E_AHI_DEVICE_TIMER0, adc_handler);
Analogue.begin(pack_bits(PIN_ANALOGUE::A1), 1);
}
1.1.3.3 - Buttons
Methods
setup()
void setup(uint8_t max_history);
The parameter max_history
is the maximum number of reference counts that can be set in begin()
. Memory allocation and initialization are performed here.
begin()
void begin(uint32_t bmPortMask,
uint8_t u8HistoryCount,
uint16_t tick_delta);
Starts the operation of Buttons
. The first parameter bmPortMask
specifies the bitmap of digital inputs to be monitored. bit 0 corresponds to DIO 0, …, bit N corresponds to DIO N. Multiple bits can be specified. The second parameter u8HistoryCount
is the number of times required to confirm a value. The third parameter tick_delta
specifies the interval for checking the value in milliseconds.
The confirmation of the value takes u8HistoryCount * tick_delta
[ms]. For example, if u8HistoryCount
=5 and tick_delta
=4, it takes at least about 20 ms to confirm the state.
The check is performed in the event handler of TickTimer
. Since it is not an interrupt handler, it is affected by processing delays, but it is sufficient for suppressing chatter of mechanical buttons and the like.
end()
void end()
Stops the operation of Buttons
.
available()
inline bool available()
Returns true
when a change is detected. It is cleared when read()
is executed.
read()
bool read(uint32_t& u32port, uint32_t& u32changed)
Called when available is true. u32port
is the bitmap of the current input DIO, and u32changed
is the bitmap of DIOs where changes were detected.
Returns false
if Buttons is not operating.
Operation Details
Initial Value Confirmation
At the time when Buttons starts operating, the input state of DIO is not confirmed. It becomes available when the value is confirmed. At this time, the MSB (bit 31) of the bitmap read by read()
is set to 1.
Since operation confirmation is required, it cannot be used for monitoring ports where the input value changes constantly.
Sleep
If Buttons is running before sleep, it will resume after waking up. After resuming, the initial confirmation is performed.
1.1.3.4 - EEPROM
Performs read and write operations on the built-in EEPROM of the TWELITE wireless microcontroller.
The built-in EEPROM has 3480 bytes available from address 0x000 to 0xEFF.
The beginning part is used for Settings (Interactive Mode), so when used together, it is recommended to use the latter half of the addresses. The amount of space consumed by the settings (Interactive Mode) depends on its implementation. Even with minimal settings, the first 256 bytes are used, so it is recommended to use addresses after that.
Methods
read()
uint8_t read(uint16_t address)
Reads data corresponding to address
from the EEPROM.
write()
void write(uint16_t address, uint8_t value)
Writes value
to address
in the EEPROM.
update()
void update(uint16_t address, uint8_t value)
Performs writing similar to write()
, but first reads the data at address
and writes only if it is different from value
. This is used to reduce the number of write cycles considering the EEPROM’s rewrite lifespan.
get_stream_helper()
auto&& get_stream_helper()
// The return type is long, so it is abbreviated as auto&&.
Obtains a helper object to perform read and write operations using the later described mwx::stream
.
Input/output using the mwx::stream
interface
Through the stream_helper
helper object, use operators and methods of mwx::stream
. Using mwx::stream
allows reading and writing of integer types such as uint16_t
and uint32_t
, fixed-length arrays of uint8_t
, and formatted output via format()
objects.
auto&& strm = EEPROM.get_stream_helper();
// The helper object's type name is long, so auto&& is used to resolve it.
You can use the <<
operator and other interfaces defined in mwx::stream
with this object.
strm.seek(1024); // Move to byte 1024
strm << format("%08x", 12345678); // Record 12345678 as an 8-character hexadecimal
strm << uint32_t(0x12ab34cd); // Record 4 bytes of 0x12ab34cd
uint8_t msg_hello[16] = "HELLO WORLD!";
strm << msg_hello; // Record byte sequence "HELLO WORLD!" (no terminator)
// Result
// 0400: 30 30 62 63 36 31 34 65 12 ab 34 cd 48 45 4c 4c
// 0 0 b c 6 1 4 e 0x12ab34cd H E L L
// 0410: 4f 20 57 4f 52 4c 44 21 00 00 00 00 ff ff ff ff
// O SP W O R L D !
Using .seek()
, the EEPROM address is moved to 1024.
The above writes an 8-byte string (00bc614e
), a 4-byte integer (0x12ab34cd
), a 16-byte byte array (HELLO WORLD!...
), and a 1-byte terminator.
strm.seek(1024);
uint8_t msg1[8];
strm >> msg1;
Serial << crlf << "MSG1=" << msg1;
// MSG1=00bc614e
uint32_t var1;
strm >> var1;
Serial << crlf << "VAR1=" << format("%08x", var1);
// VAR1=12ab34cd
uint8_t msg2[16]; // Number of characters in "HELLO WORLD!"
strm >> msg2;
Serial << crlf << "MSG2=" << msg2;
// MSG2=HELLO WORLD!
Using .seek()
, the EEPROM address is moved to 1024.
Reads the previously written data sequence. Reads an 8-byte string, a 4-byte integer, and a 16-byte string in order using the >>
operator.
1.1.3.5 - PulseCounter
There are two pulse counter systems. PC0 is assigned to PulseCounter0
, and PC1 is assigned to PulseCounter1
. The alias PulseCounter
refers to PulseCounter1
.
Methods
begin()
void begin(uint16_t refct = 0,
E_PIN_INT_MODE edge = PIN_INT_MODE::FALLING,
uint8_t debounce = 0)
Initializes the object and starts counting. The first parameter, refct
, is the reference count used to determine whether an interrupt or availability condition is met. When the count exceeds this number, it is reported to the application. A value of 0 may also be specified, in which case it will not trigger a wake-up from sleep.
The second parameter, edge
, specifies whether the interrupt is on the rising (PIN_INT_MODE::RISING
) or falling (PIN_INT_MODE::FALLING
) edge.
The third parameter, debounce
, accepts values 0, 1, 2, or 3. Settings 1 through 3 reduce the effect of noise by requiring consecutive identical values for detection.
Setting | Consecutive Samples | Max Detection Frequency |
---|---|---|
0 | - | 100kHz |
1 | 2 | 3.7kHz |
2 | 4 | 2.2kHz |
3 | 8 | 1.2kHz |
end()
void end()
Stops pulse detection.
available()
inline bool available()
If the specified count (refct
in begin()
) is 0, returns true
when the count is 1 or more.
If the specified count (refct
in begin()
) is 1 or more, returns true
when the count exceeds the specified threshold.
read()
uint16_t read()
Reads the count value. The value is reset to 0 after reading.
1.1.3.6 - Serial
mwx::stream
and performs input/output on TWELITE’s UART0.- The
Serial
object is initialized at system startup with UART0 at 115200 bps, and the initialization process is handled within the library. It can be used fromsetup()
in user code. - The
Serial1
object is provided within the library but is not initialized. To enable UART1, perform the necessary initialization proceduresSerial1.setup(), Serial1.begin()
.
setup()
, wakeup()
, or just before sleep during flush
processing.setup()
void setup(uint16_t buf_tx, uint16_t buf_rx)
Initializes the object.
- Allocates memory for TX/RX FIFO buffers
- Allocates memory for the TWE_tsFILE structure
Serial
(UART0) automatically calls setup()
within the library. There is no need for the user to call it.
Also, the buffer size for Serial
(UART0) is determined at compile time. It can be changed by macros MWX_SER_TX_BUFF
(default 768) and MWX_SER_RX_BUFF
(default 256).
Parameter | Description |
---|---|
buf_tx | FIFO buffer size for TX |
buf_rx | FIFO buffer size for RX |
begin()
void begin(unsigned long speed = 115200, uint8_t config = 0x06)
Initializes the hardware.
Serial
(UART0) automatically calls begin()
within the library. There is no need for the user to call it.Parameter | Description |
---|---|
speed | Specifies the UART baud rate |
config | When the serial_jen::E_CONF::PORT_ALT bit is specified, UART1 is initialized on ~DIO14,15 instead of ~DIO11(TxD),9(RxD). If not specified, it initializes on ~DIO11(TxD),9(RxD) instead of ~DIO14(TxD),15(RxD). |
The last two digits of the specified baud rate are rounded to zero. Also, due to hardware limitations, there may be an error from the specified baud rate.
Baud rate calculation involves division and may take processing time. When specifying 9600, 38400, or 115200, the calculation is done without division. For details, see constexpr uint16_t _serial_get_hect_baud(uint32_t baud)
.
end()
(Not implemented) Stops using the hardware.
get_tsFile()
TWE_tsFILE* get_tsFile();
Returns the structure in TWE_tsFILE*
format used by the C library.
_sSerial
structure is defined.1.1.3.7 - SerialParser
It is defined as the type mwx::serial_parser<mwx::alloc_heap<uint8_t>>
, which allocates internal buffer space from the heap during initialization (begin()
).
For details, refer to the class serparser
.
1.1.3.8 - SPI
Notes
Constants
Constant | Meaning |
---|---|
const uint8_t SPI_CONF::MSBFIRST | Set MSB as the first bit |
const uint8_t SPI_CONF::LSBFIRST | Set LSB as the first bit |
const uint8_t SPI_CONF::SPI_MODE0 | Set to SPI MODE 0 |
const uint8_t SPI_CONF::SPI_MODE1 | Set to SPI MODE 1 |
const uint8_t SPI_CONF::SPI_MODE2 | Set to SPI MODE 2 |
const uint8_t SPI_CONF::SPI_MODE3 | Set to SPI MODE 3 |
Initialization and Termination
The procedure to use the SPI bus is via the begin()
method.
begin()
void begin(uint8_t slave_select, SPISettings settings)
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
Initializes the hardware.
Parameter | Description |
---|---|
slave_select | Specifies the select pin of the target peripheral.0 : DIO19``1 : DIO0 (DIO19 is reserved)``2 : DIO1 (DIO0,19 are reserved) |
settings | Specifies the SPI bus settings.clock [Hz] specifies the SPI bus frequency. A divisor close to the specified frequency is selected. The value will be 16MHz or an even division of 16MHz.bitOrder is either SPI_CONF::MSBFIRST or SPI_CONF::LSBFIRST .dataMode is one of SPI_CONF::SPIMODE0..3 . |
Example
void setup() {
...
SPI.begin(0, SPISettings(2000000, SPI_CONF::MSBFIRST, SPI_CONF::SPI_MODE3));
...
}
void wakeip() {
...
SPI.begin(0, SPISettings(2000000, SPI_CONF::MSBFIRST, SPI_CONF::SPI_MODE3));
...
}
end()
void end()
Terminates the use of SPI hardware.
Reading and Writing
There are two types of procedures for reading and writing. Use either of them as needed.
- Member Function Version (uses the member functions below for input/output)
beginTransaction(), endTransaction(), transfer(), transfer16(), transfer32()
- Helper Class Version (stream functionality available)
transceiver
Example
The following sample code reads the temperature every second from the Analog Devices temperature sensor ADT7310 and outputs it to the serial port.
#include <TWELITE>
#include <SM_SIMPLE>
enum class STATE : uint8_t {
INTERACTIVE = 255,
INIT = 0,
INIT_WAIT,
SENSOR,
LOOP_WAIT
};
SM_SIMPLE<STATE> step;
struct SensorData {
uint8_t highByte;
uint8_t lowByte;
uint16_t rawValue;
int32_t tempValue16th;
div_result_i32 temperature;
} sensorData;
void setup() {
step.setup(); // Initialize the state machine
}
void loop() {
do {
switch (step.state()) {
case STATE::INIT: // Initial state
SPI.begin(0 /* Use DIO19 as chip select */
, { 400000UL /* Clock frequency */
, SPI_CONF::MSBFIRST
, SPI_CONF::SPI_MODE3
}
);
// Software reset
SPI.beginTransaction();
for (int i = 0; i < 4; i++) {
SPI.transfer(0xFF);
}
SPI.endTransaction();
// Start Continuous Read mode
SPI.beginTransaction();
SPI.transfer(0x54);
SPI.endTransaction();
step.set_timeout(300); // Set wait time
step.next(STATE::INIT_WAIT);
break;
case STATE::INIT_WAIT: // Wait
if (step.is_timeout()) {
step.next(STATE::SENSOR);
}
break;
case STATE::SENSOR: // Read sensor data
SPI.beginTransaction();
sensorData.highByte = SPI.transfer(0x00); // Send dummy data to generate clock signal
sensorData.lowByte = SPI.transfer(0x00); // Send dummy data to generate clock signal
SPI.endTransaction();
sensorData.rawValue = (((uint16_t)sensorData.highByte << 8) | sensorData.lowByte) >> 3;
if (sensorData.rawValue & 0x1000) {
sensorData.tempValue16th = int32_t(sensorData.rawValue) - 0x2000;
} else {
sensorData.tempValue16th = sensorData.rawValue;
}
// Calculate temperature using div100()
sensorData.temperature = div100((sensorData.tempValue16th * 100) / 16);
// Output result to serial
Serial << crlf << sensorData.temperature.format() << "°C";
step.set_timeout(1000); // Wait until next capture
step.next(STATE::LOOP_WAIT);
break;
case STATE::LOOP_WAIT: // Wait
if (step.is_timeout()) {
step.next(STATE::SENSOR);
}
break;
default:
break;
}
} while (step.b_more_loop());
}
Here, the member function interface is used.
1.1.3.8.1 - SPI (Member Function Version)
begin()
method, use beginTransaction()
to enable bus communication. When beginTransaction()
is executed, the SPI select pin is asserted. Use the transfer()
function for reading and writing. SPI performs read and write operations simultaneously.beginTransaction()
void beginTransaction()
void beginTransaction(SPISettings settings)
Starts using the SPI bus. Asserts the SPI select pin.
When called with the settings
parameter, it also configures the bus settings.
endTransaction()
void endTransaction()
Ends the use of the SPI bus. Deasserts the SPI select pin.
transfer()
, transfer16()
, transfer32()
inline uint8_t transfer(uint8_t data)
inline uint16_t transfer16(uint16_t data)
inline uint32_t transfer32(uint32_t data)
Performs read/write operations on the SPI bus. transfer()
transfers 8 bits, transfer16()
transfers 16 bits, and transfer32()
transfers 32 bits.
1.1.3.8.2 - SPI (Helper Class Version)
transceiver
, you start using the bus, and by destroying the object, you end the use of the bus.By creating the object inside the conditional expression of an if statement, the lifetime of the object is limited to the scope within the if block, and when exiting the if block, the object is destroyed and the bus release procedure is performed at that point.
uint8_t c;
if (auto&& trs = SPI.get_rwer()) { // Create object and check device communication
// The scope (curly braces) here is the lifetime of trs.
trs << 0x00; // Write 0x00 using mwx::stream interface
trs >> c; // Store the read data into c.
}
// When exiting the if block, trs is destroyed and the bus usage ends
Also, since the read/write object implements the mwx::stream
interface, operators like <<
can be used.
- Matching the bus usage start and end with the object’s lifetime improves code readability and prevents omission of release procedures.
- Unifies read/write procedures using the
mwx::stream
interface.
Read/Write
A reading method using a helper class that performs read operations and their termination procedures within the scope if() { ... }
.
inline uint8_t _spi_single_op(uint8_t cmd, uint8_t arg) {
uint8_t d0, d1;
if (auto&& x = SPI.get_rwer()) {
d0 = x.transfer(cmd); (void)d0;
d1 = x.transfer(arg);
// (x << (cmd)) >> d0;
// (x << (arg)) >> d1;
}
return d1;
}
Above, the x
object created by the get_rwer()
method is used to perform byte-wise read/write.
- The
x
object is created inside theif(...)
. At the same time, the SPI bus select pin is set. (The type is resolved by universal referenceauto&&
with type inference.) - The created
x
object definesoperator bool ()
which is used for evaluation in the conditional expression. For SPI bus, it always evaluates totrue
. - The
x
object defines the methoduint8_t transfer(uint8_t)
, which performs an 8-bit read/write transfer to SPI when called. - At the end of the
if() { ... }
scope, the destructor ofx
is called, releasing the SPI bus select pin.
get_rwer()
periph_spi::transceiver get_rwer()
Obtains a worker object used for SPI bus read/write.
Worker Object
transfer()
, transfer16()
, transfer32()
uint8_t transfer(uint8_t val)
uint16_t transfer16(uint16_t val)
uint32_t transfer32(uint32_t val)
Perform transfers of 8-bit, 16-bit, and 32-bit respectively, and return the read result with the same data width as the written data.
<<
operator
operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)
int
and uint8_t
types perform 8-bit transfers.
uint16_t
and uint32_t
types perform 16-bit and 32-bit transfers respectively.
Transfer results are stored in an internal FIFO queue of up to 16 bytes and read out by the >>
operator. Since the buffer is not large, it is assumed to be read out each time after transfer.
>>
operator
operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
null_stream(size_t i = 1)
operator >> (null_stream&& p)
Specify a variable with the same data width as the previous transfer.
If the read result is not needed, use the null_stream()
object. It skips the number of bytes specified by i
.
1.1.3.9 - TickTimer
TickTimer
is used internally by TWENET for control purposes and operates implicitly. The timer interval is 1 ms. It defines only the available()
method for writing processing that occurs every 1 ms in the loop()
function based on TickTimer events.Note that it does not necessarily become available at 1 ms intervals.
Due to the contents of the user program or internal interrupt handling of the system, significant delays may occur, and some events may be skipped.
void loop() {
if (TickTimer.available()) {
if ((millis() & 0x3FF) == 0) { // This may not be processed
Serial << '*';
}
}
}
Methods
available()
inline bool available()
Set after the TickTimer
interrupt occurs, and becomes true
in the immediate loop()
execution. It is cleared after the loop()
ends.
1.1.3.10 - Timer0 .. 4
Although the embedded object names are Timer0..4
, this page refers to them as TimerX
.
Methods
setup()
void setup()
Initializes the timer. This call allocates the required memory area.
begin()
void begin(uint16_t u16Hz, bool b_sw_int = true, bool b_pwm_out = false)
Starts the timer. The first parameter specifies the timer frequency in Hz. If the second parameter is set to true
, software interrupts are enabled. If the third parameter is set to true
, PWM output is enabled.
You can change the frequency with change_hz()
. This method allows more precise control than begin()
.
You can modify the PWM duty cycle using change_duty()
.
To describe the interrupt handler process, you need to define Application Behavior.
end()
void end()
Stops the timer operation.
available()
inline bool available()
Becomes true
in the loop()
immediately after a timer interrupt occurs, and turns false
after the loop()
finishes.
change_duty()
void change_duty(uint16_t duty, uint16_t duty_max = 1024)
Sets the duty cycle. The first parameter specifies the duty value (a smaller value brings the average waveform level closer to GND, while a larger value brings it closer to Vcc). The second parameter specifies the maximum duty value.
It is recommended to set duty_max
to one of 1024
, 4096
, or 16384
.
Although internal count value calculations involve division, these three values allow bit-shift operations instead. Other values result in heavier division calculations.
change_hz()
void change_hz(uint16_t hz, uint16_t mil = 0)
Sets the timer frequency. The second parameter specifies the fractional part (three decimal places) of the frequency as an integer. For example, to set 10.4 Hz, specify hz=10, mil=400
.
1.1.3.11 - Wire
Definition
Alias Definition
using TwoWire = mwx::periph_twowire<MWX_TWOWIRE_RCVBUFF>;
mwx::periph_wire<MWX_TWOWIRE_RCVBUFF>
can be referenced as TwoWire
.
Type Definitions
The following typedefs are used for argument and return types:
typedef uint8_t size_type;
typedef uint8_t value_type;
Notes
In addition to this explanation, several argument types are defined for write()
and writer::operator()
:
- Fixed-size array type
uint8_t cmds[]={11,12};
...
Wire.write(cmds);
initializer_list<>
typeWire.write({11,12})
Initialization and Termination
Creating a Wire
instance
The instance and necessary initialization are handled within the library. In user code, call Wire.begin()
to start using it.
When using the requestFrom()
method, you can specify the size of a FIFO queue for temporary data storage. At compile time, set the number of bytes via the macro MWX_TWOWIRE_BUFF
. The default is 32 bytes.
Example:
-DMWX_TWOWIRE_BUFF=16
begin()
void begin(
const size_type u8mode = WIRE_100KHZ,
bool b_portalt = false)
Initializes the hardware.
Parameter | Description |
---|---|
u8mode | Specifies the bus frequency. Default is 100KHz (WIRE_CONF::WIRE_100KHZ ).You can specify WIRE_CONF::WIRE_??KHZ where ?? can be 50 , 66 , 80 , 100 , 133 , 160 , 200 , 266 , 320 , 400 . |
b_portalt | Changes the hardware pin assignment. |
Example
void setup() {
...
Wire.begin();
...
}
void wakeup() {
...
Wire.begin();
...
}
Reading and Writing
There are two procedures for reading and writing. Use either as needed.
Member function version (using the member functions below for I/O)
requestFrom(), beginTransmission(), endTransmission(), write()
Helper class version (stream functionality available)
reader, writer
Others
Probe (Device Presence Check)
bool probe(uint8_t address)
Checks if the device specified by address
responds. Returns true
if the device exists.
setClock()
void setClock(uint32_t speed)
This is intended to change the bus frequency, but it performs no action.
1.1.3.11.1 - Wire (Member Function Version)
This method using member functions has relatively low abstraction and follows a general API structure similar to that provided by C language libraries. It offers a more intuitive procedure for operating a two-wire serial bus.
However, you need to explicitly manage the start and end of bus usage.
Reading
requestFrom()
size_type requestFrom(
uint8_t u8address,
size_type length,
bool b_send_stop = true)
Reads a specified number of bytes in one operation. The result is stored in a queue, so you should call the .read()
method repeatedly until the queue is empty immediately afterward.
Parameter | Description |
---|---|
u8address | I2C address to read from |
length | Number of bytes to read |
b_send_stop=true | If true , a STOP bit is issued at the end of reading |
Return type size_type | Number of bytes read. 0 indicates failure |
Code Example
int len = Wire.requestFrom(0x70, 6);
for (int i = 0; i < 6; i++) {
if (Wire.available()) {
au8data[i] = Wire.read();
Serial.print(buff[i], HEX);
}
}
// skip the rest (just in case)
// while (Wire.available()) Wire.read(); // normally, not necessary.
Writing
The writing process starts with beginTransmission()
, then proceeds with the write()
method. After the entire write operation is complete, call endTransmission()
.
#define DEV_ADDR (0x70)
const uint8_t msg[2] =
{SHTC3_SOFT_RST_H, SHTC3_SOFT_RST_L};
Wire.beginTransmission(DEV_ADDR);
Wire.write(msg, sizeof(msg));
Wire.endTransmission();
beginTransmission()
void beginTransmission(uint8_t address)
Initializes a write transfer. After the write process, call endTransmission()
promptly.
Parameter | Description |
---|---|
u8address | I2C address to write to |
write(value)
size_type write(const value_type value)
Writes a single byte.
Parameter | Description |
---|---|
value | Byte to write |
Return size_type | Number of bytes written. 0 indicates an error. |
write(*value, quantity)
size_type write(
const value_type* value,
size_type quantity)
Writes a sequence of bytes.
Parameter | Description |
---|---|
*value | Byte sequence to write |
size_type | Number of bytes |
Return size_type | Number of bytes written. 0 indicates an error. |
endTransmission()
uint8_t endTransmission(bool sendStop = true)
Finalizes the write operation.
Parameter | Description |
---|---|
sendStop = true | Issues a STOP bit |
Return uint8_t | 0: success, 4: failure |
1.1.3.11.2 - Wire (Helper Class Version)
reader, writer
that correspond to reading and writing marks the start of bus usage, and destroying the object performs the bus usage termination procedure.By creating objects inside the condition expression of an if statement, the object’s lifetime is limited to the scope of the if block. When exiting the if block, the object is destroyed, and at that time, the bus usage termination procedure is performed.
if (auto&& wrt = Wire.get_writer(...)) { // Object creation and device communication check
// The scope (curly braces) is the lifetime of wrt.
wrt << 0x00; // Write 0x00 using the mwx::stream interface
}
// wrt is destroyed when exiting the if block, and bus termination is performed
Also, since the read/write objects implement the mwx::stream
interface, operators like <<
can be used.
- Matching the start and end of bus usage with the object’s lifetime improves code readability and prevents omission of termination procedures.
- Unified reading and writing procedures via the
mwx::stream
interface.
Reading
This is a reading method using helper classes to perform reading and its termination procedure within a scope if() { ... }
.
const uint8_t DEV_ADDR = 0x70;
uint8_t au8data[6];
if (auto&& rdr = Wire.get_reader(DEV_ADDR, 6)) {
for (auto&& c: au8data) {
c = rdr();
}
}
// same above
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(SHTC3_ADDRESS, 6)) {
rdr >> u16temp;
rdr >> u8temp_csum;
rdr >> u16humd;
rdr >> u8humd_csum;
}
Above, the rdr
object generated by the get_reader()
method is used to read one byte at a time. The method parameter specifies the two-wire serial ID to read.
- The
rdr
object is created insideif(...)
. (The type is resolved as a universal referenceauto&&
by type inference.) - The created
rdr
object definesoperator bool ()
and is used for evaluation in the condition. If communication is possible with the specified ID, it returnstrue
. - The
rdr
object definesint operator () (void)
, which reads one byte from the two-wire serial bus when called. Returns-1
on failure, or the read byte value on success. - The destructor of
rdr
is called at the end of theif() { ... }
scope, issuing aSTOP
on the two-wire serial bus.
get_reader(addr, read_count=0)
periphe_wire::reader
get_reader(uint8_t addr, uint8_t read_count = 0)
Obtains a worker object used for I2C reading.
Parameter | Description |
---|---|
addr | I2C address for reading |
read_count | Number of bytes to read (if specified, a STOP bit is issued at the end of the transfer). If 0 is specified, no STOP bit is issued (some devices may work without it). |
Writing (writer
)
This is a writing method using helper classes to perform writing and its termination procedure within a scope if() { ... }
.
const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
wrt(SHTC3_TRIG_H);
wrt(SHTC3_TRIG_L);
}
// same above
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
wrt << SHTC3_TRIG_H; // int type is handled as uint8_t
wrt << SHTC3_TRIG_L;
}
Above, the wrt
object generated by the get_writer()
method is used to write one byte at a time. The method parameter specifies the two-wire serial ID to write.
- The
wrt
object is created insideif(...)
. (The type is resolved as auto to avoid long type names.) - The created
wrt
object definesoperator bool ()
and is used for evaluation in the condition. If communication is possible with the specified ID, it returnstrue
. - The
wrt
object definesint operator () (void)
, which writes one byte to the two-wire serial bus when called. Returns-1
on failure, or the written byte value on success. - The destructor of
wrt
is called at the end of theif() { ... }
scope, issuing aSTOP
on the two-wire serial bus.
get_writer()
periph_wire::writer
get_writer(uint8_t addr)
Obtains a worker object used for I2C writing.
Parameter | Description |
---|---|
addr | I2C address for writing |
Worker Object (writer)
<<
operator
operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)
int
and uint8_t
types transfer 8 bits. Data order is big-endian (higher byte transferred first).
()
operator
operator() (uint8_t val)
operator() (int val)
Writes one byte.
Worker Object (reader)
>>
operator
operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
operator >> (uint8_t(&c)[N]) // fixed array of N bytes
Reads the size of each data type. Data order is big-endian (first transferred byte is stored in the higher byte).
()
operator
int operator() (bool b_stop = false)
// example
uint8_t dat[6];
if (auto&& rdr = Wire.get_reader(0x70)) {
for(uint8_t& x : dat) {
x = rdr();
}
}
Reads one byte. Returns -1 on error, or the read byte on success.
If b_stop
is set to true
, a STOP bit is issued on that read.
Example
The following example is a measurement example for the environmental sensor pal’s temperature and humidity sensor SHTC3.
Wire.begin();
// reset (may not necessary...)
if (auto&& wrt = Wire.get_writer(0x70)) {
wrt << 0x80; // SHTC3_SOFT_RST_H
wrt << 0x05; // SHTC3_SOFT_RST_L
}
delay(5); // wait some
// start read
if (auto&& wrt = Wire.get_writer(0x70)) {
wrt << 0x60; // SHTC3_TRIG_H
wrt << 0x9C; // SHTC3_TRIG_L
}
delay(10); // wait some
// read result
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(0x70, 6)) {
rdr >> u16temp;
rdr >> u8temp_csum;
rdr >> u16humd;
rdr >> u8humd_csum;
}
// checksum 0x31, init=0xFF
if (CRC8_u8CalcU16(u16temp, 0xff) != u8temp_csum) {
Serial << format("{SHTC3 T CKSUM %x}", u8temp_csum); }
if (CRC8_u8CalcU16(u16humd, 0xff) != u8humd_csum) {
Serial << format("{SHTC3 H CKSUM %x}", u8humd_csum); }
// calc temp/humid (degC x 100, % x 100)
int16_t i16Temp = (int16_t)(-4500 + ((17500 * int32_t(u16temp)) >> 16));
int16_t i16Humd = (int16_t)((int32_t(u16humd) * 10000) >> 16);
Serial << "temp=" << int(i16Temp)
<< ",humid=" << int(i16Humd) << mwx::crlf;
1.1.4 - Classes
1.1.4.1 - MWX_APIRET
class MWX_APIRET {
uint32_t _code;
public:
MWX_APIRET() : _code(0) {}
MWX_APIRET(bool b) {
_code = b ? 0x80000000 : 0;
}
MWX_APIRET(bool b, uint32_t val) {
_code = (b ? 0x80000000 : 0) + (val & 0x7fffffff);
}
inline bool is_success() const { return ((_code & 0x80000000) != 0); }
inline bool is_fail() const { return ((_code & 0x80000000) == 0); }
inline uint32_t get_value() const { return _code & 0x7fffffff; }
inline operator uint32_t() const { return get_value(); }
inline operator bool() const { return is_success(); }
};
Constructors
MWX_APIRET()
MWX_APIRET(bool b)
MWX_APIRET(bool b, uint32_t val)
The default constructor initializes with the combination false
, 0
.
You can also explicitly construct with bool
and uint32_t
parameters.
Since a constructor with a bool
parameter is implemented, you can use true
/false
as return values, like the following example:
MWX_APIRET myfunc() {
if (...) return true;
else false;
}
Methods
is_success()
, operator bool()
inline bool is_success()
inline operator bool()
Returns true
if the MSB is set to 1
.
inline bool is_fail()
Returns true
if the MSB is 0
.
inline uint32_t get_value()
inline operator uint32_t()
Retrieves the value part from bits 0 to 30.
1.1.4.2 - alloc
smplbuf
, smplque
) to specify or allocate internal memory regions.Class Name | Description |
---|---|
alloc_attach<T> | Attach an existing buffer |
alloc_local<T, int N> | Statically allocate a buffer of N bytes internally |
alloc_heap<T> | Allocate the specified size on the heap |
For alloc_attach
and alloc_heap
, you must call the appropriate initialization method (init_???()
) depending on the allocator type.
Initialization
void attach(T* p, int n) // alloc_attach
void init_local() // alloc_local
void init_heap(int n) // alloc_heap
Initializes with buffer p
and size n
.
Methods
alloc_size()
uint16_t alloc_size()
Returns the size of the buffer.
_is_attach()
, _is_local()
, _is_heap()
These methods trigger a compile-time error using static_assert
if an incompatible allocator method is used.
1.1.4.3 - axis_xyzt
struct axis_xyzt {
int16_t x;
int16_t y;
int16_t z;
uint16_t t;
};
get_axis_{x,y,z}_iter()
/* Return type is a long template name, so we use auto&& for brevity */
auto&& get_axis_x_iter(Iter p)
auto&& get_axis_y_iter(Iter p)
auto&& get_axis_z_iter(Iter p)
Generates an iterator that accesses one of the X, Y, or Z axis elements, given an iterator to a container class holding axis_xyzt
elements.
In the following example, buf.begin()
and buf.end()
are passed to get_axis_x_iter()
and used with the std::minmax_element
algorithm to analyze the X-axis.
##include <algorithm>
void myfunc() {
// Container class
smplbuf_local<axis_xyzt, 10> buf;
// Insert test data
buf[0] = { 1, 2, 3, 4 };
buf[1] = { 2, 3, 4, 5 };
...
// Algorithm to get min and max values
auto&& minmax = std::minmax_element(
get_axis_x_iter(buf.begin()),
get_axis_x_iter(buf.end()));
Serial << "min=" << int(*minmax.first)
<< ",max=" << int(*minmax.second) << mwx::crlf;
}
get_axis_{x,y,z}()
/* Return type is a long template name, so we use auto&& for brevity */
auto&& get_axis_x(T& c)
auto&& get_axis_y(T& c)
auto&& get_axis_z(T& c)
These functions generate a virtual container class that extracts one of the X, Y, or Z axes from a container class holding axis_xyzt
elements. The generated container only implements begin()
and end()
methods, which return iterators equivalent to those from get_axis_{x,y,z}_iter()
.
##include <algorithm>
void myfunc() {
// Container class
smplbuf_local<axis_xyzt, 10> buf;
// Insert test data
buf[0] = { 1, 2, 3, 4 };
buf[1] = { 2, 3, 4, 5 };
...
// Extract the X-axis values from the queue
auto&& vx = get_axis_x(que);
// Use range-based for loop
for (auto&& e : vx) { Serial << int(e) << ','; }
// Algorithm to get min and max values
auto&& minmax = std::minmax_element(
vx.begin(), vx.end());
Serial << "min=" << int(*minmax.first)
<< ",max=" << int(*minmax.second) << mwx::crlf;
}
1.1.4.4 - packet_rx
tsRxDataApp
structure from the TWENET library.This class object can be obtained via a behavior callback function or the on_rx_packets()
method.
In packet_rx
, the packet data payload is handled via the smplbuf
container, and utility functions like expand_bytes()
simplify the interpretation of the payload.
<NWK_SIMPLE>
.Methods
get_payload()
smplbuf_u8_attach& get_payload()
Retrieves the data payload of the packet.
<NWK_SIMPLE>
, the payload begins with a header specific to <NWK_SIMPLE>
. The container returned is a subarray excluding this header. If you wish to access the header as well, refer to the tsRxDataApp
structure using get_psRxDataApp()
.get_psRxDataApp()
const tsRxDataApp* get_psRxDataApp()
Retrieves the receive structure from the TWENET C library.
get_length()
uint8_t get_length()
Returns the length of the payload. Equivalent to .get_payload().size()
.
get_lqi()
uint8_t get_lqi()
Retrieves the LQI (Link Quality Indicator).
LQI indicates the quality of wireless communication. It is expressed as a number from 0 to 255.
As a rough guideline, the values can be interpreted as follows: below 50 (poor, below -80 dBm), 50–100 (fair), 100–150 (good), and above 150 (very close to the antenna). These are merely rough indicators.
get_addr_src_long()
, get_addr_src_lid()
uint32_t get_addr_src_long()
uint8_t get_addr_src_lid()
Retrieves the source address.
get_addr_src_long()
returns the source serial number. The MSB (bit 31) is always set to 1.
get_addr_src_lid()
returns the source logical ID, which ranges from 0x00
to 0xFE
(used in <NWK_SIMPLE>
).
get_addr_dst()
uint32_t get_addr_dst()
Retrieves the destination address.
The destination address is set by the sender, and its value range depends on the address type.
Value | Description |
---|---|
The serial number is used as the destination. | Specifies the serial number as the destination. |
0x00 -0xFF | An 8-bit logical ID is used as the destination. |
is_secure_pkt()
bool is_secure_pkt()
Returns true
if the packet is encrypted; otherwise returns false
.
get_network_type()
uint8_t get_network_type()
Returns the network type of the packet as identified by the network behavior.
Value | Description |
---|---|
mwx::NETWORK::LAYERED | Packet from <NWK_LAYERED> |
mwx::NETWORK::SIMPLE | Packet from <NWK_SIMPLE> |
mwx::NETWORK::NONE | Packet not transmitted via a network (e.g., App_Twelite) |
Other | Error or unidentified packet |
1.1.4.5 - packet_tx
tsTxDataApp
structure from the TWENET C library. Objects derived from this class can be obtained via network behaviors or on_tx_comp()
.
if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
pkt << tx_addr(0x00)
<< tx_retry(0x1)
<< tx_packet_delay(0,50,10);
pack_bytes(pkt.get_payload()
, make_pair("APP1", 4)
, uint8_t(u8DI_BM)
);
pkt.transmit();
}
Creating the Object
It is created using the .prepare_tx_packet()
method of the network behavior.
if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
...
}
In the example above, the object pkt
is obtained using the_twelite.network.use<NWK_SIMPLE>()
. Although the type is inferred using auto&&
, it will be a derived class of packet_tx
.
The pkt
object returns true
or false
depending on whether the transmission queue is available. It returns false
if the transmission queue is full and no more requests can be added.
Transmission Settings
Various settings, such as the destination address, must be configured for a wireless packet to be delivered. These settings are applied by passing configuration objects as the right-hand value of the <<
operator.
pkt << tx_addr(0x00)
<< tx_retry(0x1)
<< tx_packet_delay(0,50,10);
The following describes the configuration objects used for setting up transmission.
tx_addr
tx_addr(uint32_t addr)
Specifies the destination address addr
. Refer to the network behavior specification for valid address values.
<NWK_SIMPLE>
If MSB (bit 31 =0x80000000
) is set, it indicates the destination is a serial number of a wireless module.0x00
to0xEF
indicates an 8-bit logical ID.0xFE
is broadcast to child nodes (0x01
–0xEF
), and0xFF
is broadcast to all nodes.
tx_retry
tx_retry(uint8_t u8count, bool force_retry = false)
Specifies the number of retransmissions using u8count
. If force_retry
is set to true, retransmission will occur regardless of whether the transmission succeeds.
<NWK_SIMPLE>
Sends the same packetu8count+1
times. Theforce_retry
setting is ignored.
tx_packet_delay
tx_packet_delay(uint16_t u16DelayMin,
uint16_t u16DelayMax,
uint16_t u16RetryDur)
Configures delay before transmission and retry interval. Specify u16DelayMin
and u16DelayMax
in milliseconds. Transmission will start at a random point within this interval. Retry interval is specified by u16RetryDur
, also in milliseconds.
Due to internal processing, the transmission may not start exactly at the specified timing. There is also jitter from the IEEE802.15.4 protocol. This timing jitter is generally useful for avoiding collisions in many systems.
Strict timing control is considered an exceptional use case due to the nature of IEEE802.15.4.
<NWK_SIMPLE>
This setting is valid. If the same packet arrives more than one second after the first, it will not be excluded as a duplicate. This can occur due to a long retry interval or delay in relay. Duplicate handling can be configured in<NWK_SIMPLE>
initialization.
tx_process_immediate
tx_process_immediate()
Requests that the packet be transmitted as quickly as possible. Transmission is normally triggered by a TickTimer operating every 1ms. This setting forces immediate processing. Has no effect unless used with tx_packet_delay(0,0,0)
.
Other packet transmissions in progress will be processed normally.
<NWK_SIMPLE>
This setting is valid.
tx_ack_required
tx_ack_required()
In wireless packet communication, ACK (acknowledgment) is a short packet returned by the recipient to confirm successful reception. This setting enables ACK-based transmission.
<NWK_SIMPLE>
This setting is invalid in<NWK_SIMPLE>
and causes a compile error.<NWK_SIMPLE>
does not support ACK-based communication.
tx_addr_broadcast
tx_addr_broadcast()
Specifies broadcast as the destination.
<NWK_SIMPLE>
This setting is invalid in<NWK_SIMPLE>
and results in a compile error. Instead, usetx_addr(0xFF)
for general broadcast ortx_addr(0xFE)
for broadcast to child nodes.
tx_packet_type_id
tx_packet_type_id(uint8_t)
Specifies the TWENET packet type ID (0 to 7).
<NWK_SIMPLE>
This setting is invalid in<NWK_SIMPLE>
and causes a compile error. The type ID is reserved internally and not user-configurable.
1.1.4.6 - serparser
Three class names are defined depending on how the memory buffer is managed (alloc
).
// serparser_attach : uses an existing buffer
serparser_attach
// serparser : allocates an internal buffer of N bytes
serparser_local<N>
// serparser_heap : allocates a buffer in the heap
serparser_heap
Constants (Format Type)
These are format types passed as parameters to the begin()
initializer. Two types are supported here: ASCII and binary formats.
Constant | Format Type |
---|---|
uint8_t PARSER::ASCII = 1 | ASCII format |
uint8_t PARSER::BINARY = 2 | Binary format |
About Formats
ASCII Format
The ASCII format is a method to represent a binary data sequence as a string.
For example, the byte sequence 00A01301FF123456
is represented in ASCII format as follows. It starts with :
, the checksum is B1
, and the terminator is [CR:0x0d][LF:0x0a]
.
:00A01301FF123456B1[CR][LF]
The terminating checksum can be omitted by replacing the checksum and CRLF sequence with X
. Although this makes the format more vulnerable to corrupted data, it is useful for quick tests or sending data manually.
:00A01301FF123456X
Definition
Section | Byte Count (Original) | Byte Count (Format) | Description |
---|---|---|---|
Header | 1 | : (0x3A) colon character | |
Data | N | 2N | Each byte is represented as two ASCII characters (A–F in uppercase). For example, 0x1F is represented as 1 (0x31) and F (0x46). |
Checksum | 2 | The 8-bit sum of all data bytes is calculated, and the two’s complement of the result is taken. The checksum byte is represented as two ASCII characters. For example, for 00A01301FF123456 , the sum is 0x4F, and its two’s complement is 0xB1. | |
Footer | 2 | [CR] (0x0D) and [LF] (0x0A) characters |
Binary Format
Normally, use ASCII format.
Binary format is more efficient for microcontroller-to-microcontroller communication, but it requires specialized terminals and checksum handling for manual testing, making it more difficult than ASCII.
The binary format appends a header and checksum to a binary data sequence for transmission.
For example, the byte sequence 00A01301FF123456
is represented in binary format as:
0xA5 0x5A 0x80 0x08 0x00 0xA0 0x13 0x01 0xFF 0x12 0x34 0x56 0x3D
Definition
Section | Byte Count (Original) | Byte Count (Format) | Description |
---|---|---|---|
Header | 2 | Use 0xA5 0x5A | |
Data Length | 2 | Two bytes in big-endian format with MSB (0x8000) set. For example, if the data length is 8 bytes, use 0x80 0x08 . | |
Data | N | N | Specifies the original data |
Checksum | 1 | XOR of all data bytes. For example, XOR of 00A01301FF123456 results in 0x3D . | |
Footer | (1) | Checksum effectively marks the end. When output from a wireless module, 0x04 (EOT) is appended. |
Methods
Declaration: begin()
// serparser_attach : uses an existing buffer
serparser_attach p1;
uint8_t buff[128];
p1.begin(PARSER::ASCII, buff, 0, 128);
// serparser : allocates an internal buffer of N bytes
serparser p2<128>;
p2.begin(PARSER::ASCII);
// serparser_heap : allocates a buffer on the heap
serparser_heap p3;
p3.begin(PARSER::ASCII, 128);
The declaration specifies the memory allocation class. Since this can be cumbersome, aliases are provided as shown above.
Class Name (Alias) Memory Allocation | Description |
---|---|
serparser_attach | Use an existing buffer specified via begin() |
serparser_local<N> | Allocate an internal buffer of N bytes |
serparser_heap | Allocate the specified size on the heap using the begin() method |
Call the begin()
method corresponding to the memory allocation class.
serparser_attach
void begin(uint8_t ty, uint8_t *p, uint16_t siz, uint16_t max_siz)
Uses the format specified by ty
(see formats) and the buffer pointed to by p
. The total buffer size is max_siz
, and the valid data length is specified by siz
.
This definition is especially useful when outputting a data sequence in formatted style (see >>
operator).
serparser_local<N>
- Allocate internal buffer
void begin(uint8_t ty)
Initializes using the format specified by ty
(see formats).
serparser_heap
- Allocate buffer on heap
void begin(uint8_t ty, uint16_t siz)
Initializes using the format specified by ty
and allocates siz
bytes on the heap.
get_buf()
BUFTYPE& get_buf()
Returns the internal buffer. The buffer is of type smplbuf<uint8_t, alloc>
.
parse()
inline bool parse(uint8_t b)
Processes input characters. Accepts one byte of input at a time and interprets it according to the specified format. For example, in ASCII format, the sequence :00112233X
is processed byte-by-byte (:
, 0
, 0
, … X
), and the format interpretation is completed upon receiving X
.
The parse()
parameter is the input byte. It returns true
if interpretation has completed.
parse()
again will reset the parser to the intermediate (parsing) state.Example
while (Serial.available()) {
int c = Serial.read();
if (SerialParser.parse(c)) {
// Format parsing complete, b holds the resulting data sequence (smplbuf<uint8_t>)
auto&& b = SerialParser.get_buf();
// Below is the processing for the obtained data sequence
if (b[0] == 0xcc) {
// ...
}
}
}
operator bool()
operator bool()
Returns true
if parsing has completed via parse()
, otherwise returns false
while parsing is in progress.
Example (the parse()
example can be rewritten as follows)
while (Serial.available()) {
int c = Serial.read();
SerialParser.parse(c);
if(SerialParser) {
// Format parsing complete, b holds the resulting data sequence (smplbuf<uint8_t>)
auto&& b = SerialParser.get_buf();
// ...
}
}
<<
Operator
Outputs the internal buffer to a stream (e.g., Serial) in formatted style.
Example
uint8_t u8buf[] = { 0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc };
ser_parser pout;
pout.begin(PARSER::ASCII, u8buf, 6, 6); // Specify 6 bytes from u8buf
Serial << pout;// Output to Serial in formatted style -> :112233AABBCC??[CR][LF]
1.1.4.7 - pktparser
pktparser
(parser_packet) interprets byte sequences converted by the serparser.
serparser_heap parser_ser;
void setup() {
// init ser parser (heap alloc)
parser_ser.begin(PARSER::ASCII, 256);
}
void loop() {
int c;
while ((c = Serial.read()) >= 0) {
parser_ser.parse(c);
if (parser_ser.available()) {
// get buffer object
auto&& payl = parser_ser.get_buf();
// identify packet type
auto&& typ = identify_packet_type(payl.begin(), payl.end());
// if packet type is TWELITE standard 0x81 message
if (typ == E_PKT::PKT_TWELITE) {
pktparser pkt; // packet parser object
// analyze packet data
typ = pkt.parse<TwePacketTwelite>(payl.begin(), payl.end());
if (typ != E_PKT::PKT_ERROR) { // success!
// get data object
auto&& atw = pkt.use<TwePacketTwelite>();
// display packet inforamtion
Serial << crlf << format("TWELITE: SRC=%08X LQI=%03d "
, app.u32addr_src, app.u8lqi);
Serial << " DI1..4="
<< atw.DI1 ? 'L' : 'H' << atw.DI2 ? 'L' : 'H'
<< atw.DI3 ? 'L' : 'H' << atw.DI4 ? 'L' : 'H';
}
}
}
}
}
The example above shows how to interpret a 0x81 message from the standard application. The parser_ser
object receives input from Serial and converts it to a byte sequence. This sequence is then passed to identify_packet_type()
to determine the packet type (E_PKT
). If the packet type is identified, .parse<TwePacketTwelite>()
is called to analyze the content. The result is of type TwePacketTwelite
, and the .use<TwePacketTwelite>()
function is used to retrieve the parsed object. TwePacketTwelite
is a class, but its member variables can be accessed like a struct.
parse<T>
template <class T>
E_PKT parse(const uint8_t* p, const uint8_t* e)
Parses the byte sequence.
Specify the packet type T
to be parsed. For example, use TwePacketTwelite
for a 0x81 message from the standard application.
p
and e
specify the beginning and one-past-the-end of the byte sequence.
Returns a value of type E_PKT
. If an error occurs, it returns E_PKT::PKT_ERROR
.
use<T>
template
T& use()
Returns a reference to the object corresponding to the interpreted byte sequence. Call this only after successfully executing parse<T>
.
T
must be the same type used in parse<T>
, or you can specify TwePacket
to retrieve only basic information.
1.1.4.7.1 - E_PKT
The following packet types are supported:
Name | Description |
---|---|
PKT_ERROR | Used before parsing or when the packet type cannot be determined. The TwePacket does not contain valid data. |
PKT_TWELITE | Parsed result of the 0x81 command from the standard application App_Twelite. |
PKT_PAL | Parsed format of TWELITE PAL serial output. |
PKT_APPIO | Parsed UART messages from the remote control application App_IO. |
PKT_APPUART | Parsed extended format from the serial communication application App_UART. |
PKT_APPTAG | Parsed UART messages from the wireless tag application App_Tag. Sensor-specific parts are not interpreted but returned as raw payload bytes. |
PKT_ACT_STD | Output format used by samples of Act. |
1.1.4.7.2 - identify_packet_type()
idenify_packet_type()
Determines the packet type from a byte sequence. Returns a value of E_PKT
.
E_PKT identify_packet_type(uint8_t* p, uint8_t u8len)
If the byte sequence cannot be interpreted as a known packet type, E_PKT::PKT_ERROR
is returned.
1.1.4.7.3 - TwePacket
common
member struct contains shared information such as address data.
class TwePacket {
public:
static const E_PKT _pkt_id = E_PKT::PKT_ERROR;
struct {
uint32_t tick; // System time at the time of interpretation [ms]
uint32_t src_addr; // Source address (serial number)
uint8_t src_lid; // Source address (logical ID)
uint8_t lqi; // LQI
uint16_t volt; // Voltage [mV]
} common;
};
pktparser
, to retrieve minimal shared information such as address data.1.1.4.7.3.1 - TwePacketTwelite
TwePacketTwelite
class interprets the 0x81 command from the standard application App_Twelite.
class TwePacketTwelite : public TwePacket, public DataTwelite { ... };
After executing parse<TwePacketTwelite>()
, packet information is stored in DataTwelite
.
DataTwelite
Struct
struct DataTwelite {
// Source serial number
uint32_t u32addr_src;
// Source logical ID
uint8_t u8addr_src;
// Destination logical ID
uint8_t u8addr_dst;
// Timestamp at transmission
uint16_t u16timestamp;
// Flag for low-latency transmission
bool b_lowlatency_tx;
// Number of repeat transmissions
uint16_t u8rpt_cnt;
// LQI value
uint16_t u8lqi;
// DI state (true = active, Lo/GND)
bool DI1, DI2, DI3, DI4;
// DI state bitmap (from LSB: DI1, DI2, DI3, DI4)
uint8_t DI_mask;
// True if DI has ever been active
bool DI1_active, DI2_active, DI3_active, DI4_active;
// DI active bitmap (from LSB: DI1, DI2, DI3, DI4)
uint8_t DI_active_mask;
// Module power voltage [mV]
uint16_t u16Volt;
// AD values [mV]
uint16_t u16Adc1, u16Adc2, u16Adc3, u16Adc4;
// Bitmap indicating which ADs are active (from LSB: AD1, AD2, AD3, AD4)
uint8_t Adc_active_mask;
};
1.1.4.7.3.2 - TwePacketIO
TwePacketAppIO
class interprets the standard application’s App_IO serial message (0x81).
class TwePacketAppIO : public TwePacket, public DataAppIO { ... };
Packet data details are stored in DataTwelite
after executing parse<TwePacketIO>()
.
DataAppIO
Struct
struct DataAppIO {
// Source serial number
uint32_t u32addr_src;
// Source logical ID
uint8_t u8addr_src;
// Destination logical ID
uint8_t u8addr_dst;
// Timestamp at transmission
uint16_t u16timestamp;
// Flag for low-latency transmission
bool b_lowlatency_tx;
// Number of repeat relays
uint16_t u8rpt_cnt;
// LQI value
uint16_t u8lqi;
// DI state bitmap (from LSB: DI1, DI2, DI3, DI4, ...)
uint8_t DI_mask;
// DI active (1 if in use) bitmap (from LSB: DI1, DI2, DI3, DI4, ...)
uint8_t DI_active_mask;
// Bitmap indicating whether DI is triggered by interrupt (from LSB: DI1, DI2, DI3, DI4, ...)
uint16_t DI_int_mask;
};
1.1.4.7.3.3 - TwePacketUART
TwePacketAppUart
class represents the extended format of App_UART received by the parent or repeater application App_Wings.
class TwePacketAppUART : public TwePacket, public DataAppUART
After executing parse<TwePacketUART>()
, the packet information is stored in DataAppUART
.
parse<TwePacketUART>()
will return E_PKT::PKT_ERROR
. To inspect the contents, refer directly to the original byte sequence.DataAppUART
Struct
struct DataAppUART {
/**
* source address (Serial ID)
*/
uint32_t u32addr_src;
/**
* source address (Serial ID)
*/
uint32_t u32addr_dst;
/**
* source address (logical ID)
*/
uint8_t u8addr_src;
/**
* destination address (logical ID)
*/
uint8_t u8addr_dst;
/**
* LQI value
*/
uint8_t u8lqi;
/**
* Response ID
*/
uint8_t u8response_id;
/**
* Payload length
*/
uint16_t u16paylen;
/**
* payload
*/
##if MWX_PARSER_PKT_APPUART_FIXED_BUF == 0
mwx::smplbuf_u8_attach payload;
##else
mwx::smplbuf_u8<MWX_PARSER_PKT_APPUART_FIXED_BUF> payload;
##endif
};
payload
represents the data portion, but the storage method varies depending on the macro definition.
If MWX_PARSER_PKT_APPUART_FIXED_BUF
is set to 0
during compilation, payload
will reference the byte sequence directly. If the original byte sequence is modified, the data in payload
may become corrupted.
If MWX_PARSER_PKT_APPUART_FIXED_BUF
is defined with a value greater than 0
, a buffer of that size (in bytes) is allocated for payload
. However, if the size of the serial data exceeds the buffer, parse<TwePacketAppUART>()
will fail and return E_PKT::PKT_ERROR
.
1.1.4.7.3.4 - TwePacketPAL
TwePacketPal
class interprets packet data from TWELITE PAL. This class provides a common interface for handling TWELITE PAL packets (e.g., sensor data sent upstream).
class TwePacketPal : public TwePacket, public DataPal { ... };
Common PAL data is defined in DataPal
.
Generator functions are provided to extract sensor-board-specific data for each type of PAL.
DataPal
Struct
The data structure of PAL packets varies depending on the connected sensor, but DataPal
holds the common part of the data structure.
struct DataPal {
uint8_t u8lqi; // LQI value
uint32_t u32addr_rpt; // Address of repeater
uint32_t u32addr_src; // Source address
uint8_t u8addr_src; // Source logical address
uint16_t u16seq; // Sequence number
E_PAL_PCB u8palpcb; // Type of PAL board
uint8_t u8palpcb_rev; // Revision of PAL board
uint8_t u8sensors; // Number of sensor data entries included (MSB=1 indicates error)
uint8_t u8snsdatalen; // Length of sensor data (in bytes)
union {
const uint8_t *au8snsdata; // Pointer to sensor data
uint8_t _pobj[MWX_PARSER_PKT_APPPAL_FIXED_BUF]; // Sensor-specific objects
};
};
A PAL packet consists of two main blocks: the common PAL part and a sensor-specific data part. The sensor-specific part is stored as-is without parsing. To simplify handling, data exceeding 32 bytes is stored in uptr_snsdata
, which is dynamically allocated.
The sensor-specific part is stored in a structure that inherits from PalBase
. This structure is generated by generator functions defined in TwePacketPal
.
When parse<TwePacketPAL>()
is executed and the data fits within MWX_PARSER_PKT_APPPAL_FIXED_BUF
, sensor-specific objects are created.
If it exceeds that size, a reference to the raw byte sequence is stored in au8snsdata
.
In such cases, if the original byte sequence is modified, sensor-specific objects can no longer be generated.
PalBase
All sensor-specific structures for PAL inherit from PalBase
, which contains the sensor data storage status u32StoredMask
.
struct PalBase {
uint32_t u32StoredMask; // Internal flag indicating which data is stored
};
PalEvent
A PAL event does not directly transmit raw sensor data, but rather processed information triggered under specific conditions. For example, when acceleration exceeds a threshold from a stationary state.
struct PalEvent {
uint8_t b_stored; // True if stored
uint8_t u8event_source; // Reserved
uint8_t u8event_id; // Event ID
uint32_t u32event_param;// Event parameter
};
If event data is present, .is_PalEvent()
in TwePacketPal
returns true
, and .get_PalEvent()
provides the PalEvent
structure.
Generator Functions
Generator functions are provided to extract sensor-board-specific data for each type of PAL.
void print_pal(pktparser& pkt) {
auto&& pal = pkt.use<TwePacketPal>();
if (pal.is_PalEvent()) {
PalEvent obj = pal.get_PalEvent();
} else
switch(pal.u8palpcb) {
case E_PAL_PCB::MAG:
{
// generate pal board specific data structure.
PalMag obj = pal.get_PalMag();
} break;
case E_PAL_PCB::AMB:
{
// generate pal board specific data structure.
PalAmb obj = pal.get_PalAmb();
} break;
...
default: ;
}
}
To use generator functions, first check whether pkt
is an event using .is_PalEvent()
. If so, retrieve the data using get_PalEvent()
. Otherwise, generate the appropriate object based on u8palpcb
.
get_PalMag()
PalMag get_PalMag()
// MAG
struct PalMag : public PalBase {
uint16_t u16Volt; // Module voltage [mV]
uint8_t u8MagStat; // Magnetic switch state [0: no magnet, 1, 2]
uint8_t bRegularTransmit; // MSB flag of u8MagStat
};
If .u8palpcb == E_PAL_PCB::MAG
, retrieve PalMag
data for the open-close sensor PAL.
get_PalAmb()
PalAmb get_PalAmb()
// AMB
struct PalAmb : public PalBase {
uint16_t u16Volt; // Module voltage [mV]
int16_t i16Temp; // Temperature (value ×100)
uint16_t u16Humd; // Humidity (value ×100)
uint32_t u32Lumi; // Illuminance (approx. lux)
};
If .u8palpcb == E_PAL_PCB::AMB
, retrieve PalAmb
data for the environmental sensor PAL.
get_PalMot()
PalMot get_PalMot()
// MOT
struct PalMot : public PalBase {
uint16_t u16Volt; // Module voltage [mV]
uint8_t u8samples; // Number of samples
uint8_t u8sample_rate_code; // Sample rate (0: 25Hz, 4: 100Hz)
int16_t i16X[16]; // X-axis
int16_t i16Y[16]; // Y-axis
int16_t i16Z[16]; // Z-axis
};
If .u8palpcb == E_PAL_PCB::MOT
, retrieve PalMot
data for the motion sensor PAL.
get_PalEvent()
PalEvent get_PalEvent()
// PAL event
struct PalEvent {
uint8_t b_stored; // True if event information is available
uint8_t u8event_source; // Event source
uint8_t u8event_id; // Event ID
uint32_t u32event_param; // 24-bit event parameter
};
If .is_PalEvent()
is true
, retrieve PalEvent
data.
1.1.4.8 - smplbuf
template <typename T, int N> smplbuf_local
template <typename T> smplbuf_attach
template <typename T> smplbuf_heap
smplbuf
is a container class that provides array operations for a memory region specified by the element type T
and the memory allocation method alloc
. Since specifying alloc
directly is cumbersome, aliases are defined using using
.
Below is an example of object declaration. After declaration, call an initialization method. Each object starts with a maximum size of 128 bytes and a current size of 0. Expand the size as needed during use.
// Array area is a fixed array as a class member variable
smplbuf_local<uint8_t, 128> b1;
// Array area references an existing buffer
uint8_t buf[128];
smplbuf_attach<uint8_t> b2(;
// Array area is allocated on the heap
smplbuf_heap<uint8_t> b3;
// Initialization (if defined globally, do this in setup())
void setup() {
b1.init_local();
b2.attach(buf, 0, 128);
b3.init_heap(128);
}
// Inside a processing function
void some_func() {
smplbuf_local<uint8_t, 128> bl;
// Can be omitted if smplbuf_local is defined locally
bl.push_back('a');
}
Aliases are available for the uint8_t
type only.
template <int N>
smplbuf_u8
// smplbuf<uint8_t, alloc_local<uint8_t, N>>
smplbuf_u8_attach
// smplbuf<uint8_t, alloc_attach<uint8_t>>
smplbuf_u8_heap
// smplbuf<uint8_t, alloc_heap<uint8_t>>
You can access elements using the []
operator like a normal array, and also use iterators.
void begin() { // begin() runs only once at startup
smplbuf_u8<32> b1;
b1.reserve(5); // Initializes 5 bytes of usable area (accessible via b1[0..5])
b1[0] = 1;
b1[1] = 4;
b1[2] = 9;
b1[3] = 16;
b1[4] = 25;
for(uint8_t x : b1) { // Loop using .begin() and .end() implicitly
Serial << int(x) << ",";
}
}
The push_back()
method is defined, allowing algorithms that append data to the end.
Declaration and Initialization
smplbuf_local<T,N>()
smplbuf_local<T,N>::init_local()
smplbuf_attach<T>(T* buf, uint16_t size, uint16_t N)
smplbuf_attach<T>::attach(T* buf, uint16_t size, uint16_t N)
smplbuf_heap<T>()
smplbuf_heap<T>::init_heap(uint16_t N)
// Example
// Fixed-size internal array
smplbuf_local<uint8_t, 128> b1;
b1.init_local();
// Using an existing array
uint8_t buf[128];
smplbuf_attach<uint8_t> b2;
b2.attach(buf, 0, 128);
// Allocated on the heap
smplbuf_heap<uint8_t> b3;
b3.init_heap(128);
Declares a container of type T
and size N
. Call an initialization method after declaration.
smplbuf_local
allocates memory using an internal fixed array. Initialization via constructor is also supported.
smplbuf_attach
requires the pointer to the buffer T* buf
, the initial size size
, and the maximum size N
. Initialization via constructor is also supported.
smplbuf_heap
allocates memory in the heap (a memory region that cannot be released but can be allocated at runtime). Since the memory cannot be freed once allocated, it is typically used as a global object. Memory allocation is done via init_heap()
. Allocation via constructor is not supported; always use init_heap()
.
init_local()
, attach()
, or init_heap()
) at the start of execution (e.g., in setup()
).Initializer List
void in_some_func() {
smplbuf_local<uint8_t, 5> b1;
b1.init_local();
b1 = { 0, 1, 2, 3, 4 };
smplbuf_local<uint8_t, 5> b2{0, 1, 2, 3, 4};
}
Members can be initialized using an initializer list { ... }
. Except for local declarations of smplbuf_local
, you must call an initialization method first.
- As the right-hand value of an assignment (
smplbuf_local
,smplbuf_attach
,smplbuf_heap
) - Constructor (for local declarations of
smplbuf_local
, not allowed in global scope)
Methods
append()
, push_back()
, pop_back()
inline bool append(T&& c)
inline bool append(const T& c)
inline void push_back(T&& c)
inline void push_back(const T& c)
inline void pop_back()
Adds the member c
to the end. append()
returns a bool
, which is false
if the buffer is full and the element cannot be added.
pop_back()
removes the last entry. Note that it does not clear the content.
empty()
, size()
, capacity()
inline bool empty()
inline bool is_end()
inline uint16_t size()
inline uint16_t capacity()
empty()
returns true
if the array has no elements. Conversely, is_end()
returns true
when the array is full.
size()
returns the number of elements in the array.
capacity()
returns the maximum number of elements the array can hold.
reserve()
, reserve_head()
, redim()
inline bool reserve(uint16_t len)
inline void reserve_head(uint16_t len)
inline void redim(uint16_t len)
reserve()
expands the array size. The newly allocated region is initialized by default.
reserve_head()
reserves space at the head of the array that is not accessible via the container. This can be used, for example, when accessing a subarray after skipping the header of a packet payload. To restore access to the reserved region, provide the same negative value used during reservation.
redim()
changes the size of the active region. Unlike reserve()
, it does not initialize unused areas.
operator []
inline T& operator [] (int i)
inline T operator [] (int i) const
Accesses an element by index.
If a negative value is given to i
, the element is accessed from the end. -1
refers to the last element, -2
to the second last, and so on.
Output to mwx::stream
Array objects of type uint8_t
(smplbuf<uint8_t, *>
) can be directly output to derived objects of mwx::stream
.
<<
Operator
template <class L_STRM, class AL>
mwx::stream<L_STRM>& operator << (
mwx::stream<L_STRM>& lhs, mwx::_smplbuf<uint8_t, AL>& rhs)
//例
smplbuf_u8<128> buf;
buf.push_back('a');
buf.push_back('b');
buf.push_back('c');
Serial << buf;
// Output: abc
Outputs the byte array to a derived object of mwx::stream
, such as Serial
.
to_stream()
inline std::pair<T*, T*> to_stream()
// Example
smplbuf_u8<128> buf;
buf.push_back('a');
buf.push_back('b');
buf.push_back('c');
Serial << buf.to_stream();
// Output: 0123
Used for stream output purposes. This method is used in the implementation of the <<
operator.
Generating Data with mwx::stream
mwx::stream
provides functions and operators such as the <<
operator and printfmt()
method for outputting byte arrays to a stream. You can use a smplbuf
array of uint8_t
as a stream output target.
There are two methods.
- Use the helper object generated by
get_stream_helper()
. - Use the smplbuf class that inherits
mwx::stream
.
1.1.4.8.1 - get_stream_helper()
mwx::stream
via the stream_helper
that refers to a uint8_t
smplbuf array.
smplbuf_u8<32> b;
auto&& bs = b.get_stream_helper(); // helper object
// Generate data sequence
uint8_t FOURCHARS[]={'A', 'B', 'C', 'D'};
bs << FOURCHARS;
bs << ';';
bs << uint32_t(0x30313233); // "0123"
bs << format(";%d", 99);
Serial << b << crlf; // output to Serial via smplbuf_u8<32> class
// Result: ABCD;0123;99
Since the type name of the helper object can be long, it is resolved using auto&&
. You can use interfaces defined by mwx::stream
, such as the <<
operator, with this object.
The created helper object bs
starts reading and writing from the head of the base array b
. If at the end of the array, data is appended using append()
. The position advances with each read/write operation.
The helper function supports the >>
operator for reading.
// ...continued from the above example
// ABCD;0123;99 <- stored in b
// Variables to store read data
uint8_t FOURCHARS_READ[4];
uint32_t u32val_read;
uint8_t c_read[2];
// Read using >> operator
bs.rewind(); // rewind position to the start
bs >> FOURCHARS_READ; // 4 characters
bs >> mwx::null_stream(1); // skip 1 character
bs >> u32val_read; // 32-bit data
bs >> mwx::null_stream(1); // skip 1 character
bs >> c_read; // 2 characters
// Display results
Serial << crlf << "4chars=" << FOURCHARS_READ;
Serial << crlf << format("32bit val=0x%08x", u32val_read);
Serial << crlf << "2chars=" << c_read;
// 4chars=ABCD
// 32bit val=0x30313233
// 2chars=99
1.1.4.8.2 - smplbuf_strm_u8
smplbuf_strm_u8???
type for uint8_t
also implements the stream interface, allowing use of several stream-related methods.
// smplbuf_strm_u8<N> : local allocation
template <int N> using smplbuf_strm_u8
= _smplbuf_stream<uint8_t, mwx::alloc_local<uint8_t, N>>;
// smplbuf_strm_u8_attach : attaches to existing buffer
using smplbuf_strm_u8_attach
= mwx::_smplbuf_stream<uint8_t, mwx::alloc_attach<uint8_t>>;
// smplbuf_strm_u8_heap : heap allocation
using smplbuf_strm_u8_heap
= mwx::_smplbuf_stream<uint8_t, mwx::alloc_heap<uint8_t>>;
// Definition of << operator
template <class L_STRM, class ALOC>
mwx::stream<L_STRM>& operator << (
mwx::stream<L_STRM>& lhs,
mwx::_smplbuf_stream<uint8_t, ALOC>& rhs)
{
lhs << rhs.to_stream();
return lhs;
}
Example
smplbuf_strm_u8<128> sb1;
sb1 << "hello";
sb1 << uint32_t(0x30313233);
sb1 << format("world%d",99);
sb1.printfmt("Z!");
Serial << sb1;
// hello0123world99Z!
1.1.4.9 - smplque
template <typename T, int N, class Intr> smplbuf_local
template <typename T, class Intr> smplbuf_attach
template <typename T, class Intr> smplbuf_heap
smplque
is a container class that provides FIFO queue operations on a memory region specified by the element type T
and the memory allocation method alloc
. Since specifying alloc
can be complicated, alias definitions using using
are provided.
You can register a class Intr
that sets interrupt disabling settings at declaration. If not specified, the default behavior will not perform any interrupt control.
Here are examples of object declarations. Initialization methods are called right after declaration. In all cases, the maximum size immediately after initialization is 128 bytes, and the initial size is 0, meaning nothing is stored. The maximum size cannot be changed.
void some_func() {
// Uses internal fixed-size array
smplque_local<uint8_t, 128> q1;
// Uses an existing array
uint8_t buf[128];
smplque_attach<uint8_t> q2;
// Allocates on the heap
smplque_heap<uint8_t> q3;
}
void setup() {
// Initialize global objects in setup()
q1.init_local();
q2.attach(buf, 128);
q3.init_heap(128);
}
void some_func() {
// Local smplque_local can omit init_local()
smplque_local<uint8_t, 128> q_local;
..
}
As a FIFO queue, it is operated using methods such as push()
, pop()
, and front()
.
void begin() { // begin() runs only once at startup
smplque_local<int, 32> q1;
q1.push(1);
q1.push(4);
q1.push(9);
q1.push(16);
q1.push(25);
while(!q1.empty()) {
Serial << int(q1.front()) << ',';
q1.pop();
}
// output -> 1,4,9,16,25,
}
Access using iterators is also possible.
void begin() { // begin() runs only once at startup
smplque_local<int, 32> q1;
q1.init_local();
q1.push(1);
q1.push(4);
q1.push(9);
q1.push(16);
q1.push(25);
// Using iterator
for(int x : q1) {
Serial << int(x) << ',';
}
// Using STL algorithms
auto&& minmax = std::minmax_element(q1.begin(), q1.end());
Serial << "min=" << int(*minmax.first)
<< ",max=" << int(*minmax.second);
// output -> 1,4,9,16,25,min=1,max=25[]
}
Declaration and Initialization
smplbuf_local<T,N>
smplbuf_local<T,N>::init_local()
smplbuf_attach<T>
smplbuf_attach<T>::attach(T* buf, uint16_t N)
smplbuf_heap<T>
smplbuf_heap<T>::init_heap(uint16_t N);
// Example
// Uses internal fixed-size array
smplque_local<uint8_t, 128> q1;
q1.init_local();
// Uses an existing array
uint8_t buf[128];
smplque_attach<uint8_t> q2;
q2.attach(buf, 128);
// Allocates on the heap
smplque_heap<uint8_t> q3;
q3.init_heap(128);
Declare a container of type T
and size N
. After declaration, call the initialization method.
smplque_local
allocates space with an internal fixed-size array. It can also be initialized using a constructor.
smplque_attach
requires the pointer to the buffer to use (T* buf
), the initial size of the array, and the maximum size N
. It can also be initialized using a constructor.
smplque_heap
allocates memory in the HEAP area (memory that cannot be released but can be allocated at any time). Since it cannot be released once allocated, it is usually defined in the global scope. The memory allocation is performed by calling init_heap()
. Memory allocation via constructor is not possible. Always call init_heap()
to use it.
init_local()
, attach()
, or init_heap()
during the early stage of execution (preferably in setup()
).Methods
push()
, pop()
, front()
, back()
inline void push(T&& c)
inline void push(T& c)
inline void pop()
inline T& front()
inline T& back()
inline T& pop_front()
push()
adds an entry to the queue.
pop()
removes an entry from the queue.
front()
accesses the first entry (the one added first).
back()
accesses the last entry (the one added last).
pop_front()
returns the first entry and simultaneously removes it from the queue.
empty()
, size()
, is_full()
inline bool empty()
inline bool is_full()
inline uint16_t size()
inline uint16_t capacity()
empty()
returns true
if the queue has no elements. is_full()
returns true
when the queue is full.
size()
returns the number of elements currently in the queue.
capacity()
returns the maximum number of elements the queue can hold.
clear()
inline void clear()
Removes all elements from the queue.
operator []
inline T& operator[] (int i)
Accesses the element at index i
. 0
is the first added element.
Iterator
inline smplque::iterator begin()
inline smplque::iterator end()
Returns iterators via begin()
and end()
. The beginning iterator points to the first element added to the queue. By using iterators, you can use range-based for loops and algorithms.
As an advanced usage, see iterator access focusing on specific members of the axis_xyzt
structure.
1.1.4.10 - Input/Output Stream
- Provides interfaces to several classes (
Serial, Wire, SPI, smplbuf
) using polymorphism with the CRTP (Curiously Recurring Template Pattern) method.- In CRTP, derived classes are defined as
template class Derived : public stream<Derived>;
, allowing the base class to also refer to methods of the derived class.
- In CRTP, derived classes are defined as
- This class defines common processing such as the
print
method and the<<
operator, and calls methods likewrite()
implemented in derived classes, achieving an implementation similar to using virtual functions.
Interface (Implemented in Derived Classes)
Derived classes implement the following functions.
available()
int available()
// example
while(Serial.available()) {
int c = Serial.read();
// ... any
}
Returns 1 if input exists, 0 if not.
Parameter | Description |
---|---|
Return int | 0: No data 1: Data available |
flush()
void flush()
// example
Serial.println("long long word .... ");
Serial.flush();
Flushes the output (waits until output is complete).
read()
int read()
// example
int c;
while (-1 != (c = read())) {
// any
}
Reads one byte of data from the stream. Returns -1
if no data is available.
write()
size_t write(int c)
// example
Serial.write(0x30);
Outputs one byte to the stream.
Parameter | Description |
---|---|
n | The character to output. |
Return size_t | 1 if output succeeded, 0 if failed. |
vOutput()
static void vOutput(char out, void* vp)
A static function that outputs one byte. Since it is not a class method, member variables cannot be used. Instead, a pointer to the class instance is passed as the parameter vp.
This static function is used internally and passed as a function pointer for one-byte output to fctprintf()
. It is used to implement methods like print
.
Parameter | Description |
---|---|
out | The character to output |
vp | Pointer to the class instance Usually cast back to the original class to call the write() method |
Interface
putchar()
void mwx::stream::putchar(char c)
// example
Serial.putchar('A');
// result -> A
Outputs one byte.
print()
, println()
size_t print(T val, int base = DEC) // T: integer type
size_t print(double val, int place = 2)
size_t print(const char*str)
size_t print(std::initializer_list<int>)
// example
Serial.print("the value is ");
Serial.print(123, DEC);
Serial.println(".");
// result -> the value is 123.
Serial.print(123.456, 1);
// result -> 123.5
Serial.print({ 0x12, 0x34, 0xab, 0xcd });
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Performs various formatted outputs.
Parameter | Description |
---|---|
val | The numeric type to format and output |
base | Output format BIN binary / OCT octal / DEC decimal / HEX hexadecimal |
place | Number of decimal places |
Return size_t | Number of bytes written |
printfmt()
size_t printfmt(const char* format, ...);
// example
Serial.printfmt("the value is %d.", 123);
// result -> the value is 123.
Outputs formatted output in printf style.
See TWESDK/TWENET/current/src/printf/README.md
operator <<
// examples
Serial << "this value is" // const char*
<< int(123)
<< '.';
<< mwx::crlf;
// result -> this value is 123.
Serial << fromat("this value is %d.", 123) << twe::crlf;
// result -> this value is 123.
Serial << mwx::flush; // flush here
Serial << bigendian(0x1234abcd);
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Serial << int(0x30) // output 0x30=48, "48"
<< '/'
<< uint8_t(0x31); // output '1', not "48"
// result -> 48/1
smplbuf<char,16> buf = { 0x12, 0x34, 0xab, 0xcd };
Serail << but.to_stream();
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Seiral << make_pair(buf.begin(), buf.end());
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Serial << bytelist({ 0x12, 0x34, 0xab, 0xcd });
// will output 4byte of 0x12 0x34 0xab 0xcd in binary.
Argument Type | Description |
---|---|
char | Outputs one byte (does not format as a number) |
int | Outputs integer (printf “%d”) |
double | Outputs number (printf “%.2f”) |
uint8_t | Outputs one byte (same as char type) |
uint16_t | Outputs 2 bytes (big endian order) |
uint32_t | Outputs 4 bytes (big endian order) |
const char*``uint8_t*``const char[S] | Outputs up to the terminating character. The terminator is not included in output. (S is fixed array size) |
uint8_t[S] | Outputs S bytes of the array as is. (S is fixed array size) |
format() | Outputs in printf format |
mwx::crlf | Outputs newline CRLF |
mwx::flush | Flushes output |
bigendian() | Outputs numeric types in big endian order (rvalue) |
std::pair<T*, T*> | Pair containing begin(), end() pointers of byte type. Can be generated by make_pair . T is assumed to be uint8_t . (rvalue) |
bytelist() | Outputs byte sequence using std::initializer_list |
smplbuf<uint8_t,AL>& | Outputs contents of an array class of type uint8_t . ALC is memory allocation method. |
smplbuf<uint8_t, AL>::to_stream() | Outputs data of smplbuf<T> T is uint8_t type, AL is memory allocation method. |
uint8_t, uint16_t, uint32_t
types. When outputting numbers as strings, explicitly cast to int
.uint8_t[S]
type which considers size.set_timeout()
, get_error_status()
, clear_error_status()
uint8_t get_error_status()
void clear_error_status()
void set_timeout(uint8_t centisec)
// example
Serial.set_timeout(100); // Set timeout to 1000ms
uint8_t c;
Serial >> c;
Manages input timeout and errors using the >>
operator.
Specify the timeout duration with set_timeout()
, and perform input with the >>
operator. If input is not obtained within the specified time, error value can be read with get_error_status()
. Clear error status with clear_error_status()
.
Argument Type | Description |
---|---|
centisec | Sets timeout duration in 1/10 second units. Specifying 0xff disables timeout. |
Error Values
Value | Meaning |
---|---|
0 | No error |
1 | Error status |
operator >>
inline D& operator >> (uint8_t& v)
inline D& operator >> (char_t& v)
template <int S> inline D& operator >> (uint8_t(&v)[S])
inline D& operator >> (uint16_t& v)
inline D& operator >> (uint32_t& v)
inline D& operator >> (mwx::null_stream&& p)
//// Example
uint8_t c;
the_twelite.stop_watchdog(); // Stop the watchdog
Serial.set_timeout(0xFF); // No timeout
// Read one byte
Serial >> c;
Serial << crlf << "char #1: [" << c << ']';
// Discard bytes
Serial >> null_stream(3); // Discard 3 bytes
Serial << crlf << "char #2-4: skipped";
// Read 4 bytes (fixed-length array of uint8_t only)
uint8_t buff[4];
Serial >> buff;
Serial << crlf << "char #5-8: [" << buff << "]";
Performs input.
- Cannot be executed inside
setup()
. - Polling wait is performed, so depending on timeout setting (e.g., no timeout), the watchdog timer may trigger and reset.
Usually, reading is done as follows inside loop()
.
void loop() {
uint8_t c;
while(Serial.available()) {
Serial >> c;
// or c = Serial.read();
switch(c) { ... } // Branch processing based on c value
}
}
Below are the types that can be read and stored.
Argument Type | Description |
---|---|
uint8_t, char_t | Reads one byte |
uint16_t | Reads 2 bytes (big endian order) |
uint32_t | Reads 4 bytes (big endian order) |
uint8_t[S] | Reads S bytes (S is fixed array size) |
null_stream(int n) | Discards n bytes |
1.1.4.10.1 - mwx::mwx_format
<<
operator of mwx::stream
.Within the library, it is aliased as Using format=mwx::mwx_format;
.
Serial << format("formatted print: %.2f", (double)3123 / 100.) << mwx::crlf;
// formatted print: 31.23[newline]
- Store the argument list received by the constructor into internal class variables using parameter pack expansion
- When
operator <<
is called, callfctprintf()
and write data to the stream
Constructor
format(const char *fmt, ...)
The constructor saves the format pointer and parameters. The following <<
operator call interprets the format and performs output processing.
Parameter | Description |
---|---|
fmt | Format string. See TWESDK/TWENET/current/src/printf/README.md |
... | Parameters corresponding to the format string. ※ The maximum number is 4; using 5 or more parameters will cause a compile error. ※ Consistency with the format is not checked, so unsafe for inconsistent input. |
fmt
must remain accessible until this object is destroyed.1.1.4.10.2 - mwx::bigendian
<<
operator of mwx::stream
.
Serial << mwx::bigendian(0x1234abcdUL);
// output binary -> 0x12 0x34 0xab 0xcd
Constructor
template <typename T>
bigendian::bigendian(T v)
Parameter | Description |
---|---|
v | A value of type uint16_t or uint32_t |
1.1.4.10.3 - mwx::crlf
<<
operator of mwx::stream
.
Serial << "hello world!" << mwx::crlf;
1.1.4.10.4 - mwx::flush
mwx::stream
.An instance of a helper class that calls the flush()
method.
for (int i = 0; i < 127; ++i) {
Serial << "hello world! (" << i << ")" << twe::endl << twe::flush;
}
- In the case of a serial port, polling wait is performed until output is complete
- In the case of an
mwx::simpbuf
buffer,0x00
is output at the end (size does not change)
1.1.4.10.5 - stream_helper
stream_helper
is a helper object that provides the mwx::stream
interface. It generates a helper object that references a data class, and performs data input/output through the helper object.Below, a helper object bs
is generated from the array b
of smplbuf, and data input is performed using the mwx::stream::operator <<()
operator.
smplbuf_u8<32> b;
auto&& bs = b.get_stream_helper(); // Helper object
// Generate data sequence
uint8_t FOURCHARS[]={'A', 'B', 'C', 'D'};
bs << FOURCHARS;
bs << ';';
bs << uint32_t(0x30313233); // "0123"
bs << format(";%d", 99);
Serial << b << crlf; // Output to Serial is via smplbuf_u8<32> class
// Result: ABCD;0123;99
Overview
stream_helper
behaves as if the data array is a stream.
Internally, it keeps track of the read/write position within the data array. It behaves as follows:
- When reading or writing, the read/write position moves to the next position.
- After reading the last data or appending data to the end, the read/write position becomes the end position.
- When the read/write position is at the end,
available()
returnsfalse
.- Reading is not possible.
- Writing appends data if within writable range.
Creating stream_helper
stream_helper
is created from member functions of data classes (smplbuf, EEPROM).
auto&& obj_helper = obj.get_stream_helper()
// obj is an object of a data class, and obj_helper's type is long, so it is received with auto&&.
Methods
rewind()
void rewind()
Moves the read/write position to the beginning.
seek()
int seek(int offset, int whence = MWX_SEEK_SET)
Sets the read/write position.
whence | Position set |
---|---|
MWX_SEEK_SET | Sets from the beginning. offset of 0 means the same as rewind() . |
MWX_SEEK_CUR | Moves by offset from the current position. |
MWX_SEEK_END | Sets to the end position. offset of 0 sets to the end. -1 moves to the last character. |
tell()
int tell()
Returns the read/write position. Returns -1
if at the end position.
available()
int available()
Returns 0
if the read/write position is at the end. Otherwise, returns a non-zero value.
1.1.4.11 - SM_SIMPLE State Machine
SM_SIMPLE
is used in sample code for handling state transitions, waiting for timeouts, transmission completion, and similar processing.Here is a basic example of SM_SIMPLE
.
##include <SM_SIMPLE>
enum class STATE : uint8_t {
INIT = 0,
SENSOR,
TX,
TX_WAIT_COMP,
GO_SLEEP
};
SM_SIMPLE<STATE> step;
begin() {
...
step.init(); // Initialization
}
loop() {
do {
switch(step.state()) {
case STATE::INIT:
...
step.next(STATE::SENSOR);
break;
case STATE::SENSOR:
...
step.next(STATE::TX);
break;
case STATE::TX:
if (/* Transmission request successful */) {
step.set_timeout(100); // Set timeout
step.clear_flag(); // Waiting for completion
step.next(STATE::TX_WAIT_COMP);
}
break;
case STATE::TX_WAIT_COMP:
if (step.is_timeout()) the_twelite.reset_system(); // Timeout
if (step.is_flag_ready()) sleepNow(); // Flag was set
break;
...
}
} while(step.b_more_loop());
}
void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled) {
step.set_flag(ev.bStatus);
}
void sleepNow() {
step.on_sleep(false); // Reset state machine
the_twelite.sleep(10000); // 10 sec
}
Explanation
To use SM_SIMPLE
, define an enum class
that lists the states. In the example above, this is defined as STATE
. You create a class object like SM_SIMPLE<STATE> step;
using the enum as the template parameter. Then call .setup()
on the object to initialize it.
enum class STATE : uint8_t {
INIT = 0,
SENSOR,
TX,
TX_WAIT_COMP,
GO_SLEEP
};
SM_SIMPLE<STATE> step;
void setup() {
step.init();
}
The initial state of SM_SIMPLE
has a value of 0, which corresponds to STATE::INIT
in the above example. To get the current state, use .state()
and use it in a switch
statement inside a do while
loop as shown.
loop() {
do {
switch(step.state()) {
case STATE::INIT: // State with value 0
...
To transition states, call .next()
. When the state changes, b_more_loop()
returns true
and the do while
loop executes again. In the example, calling .next(STATE::TX)
from STATE::SENSOR
causes another loop iteration, executing the case STATE::TX:
block. If the state does not change, the loop exits, and loop()
ends until the next call.
do {
switch(step.state()) {
...
case STATE::SENSOR:
...
step.next(STATE::TX); // (1) State transition
break;
case STATE::TX: // (3) Called on second loop
if (/* Transmission request successful */) {
...
}
} while (b_more_loop()); // (2) Loop continuation check
To wait for completion of processing (e.g., transmission complete), call .clear_flag()
and later call .set_flag(uint32_t)
from a callback or similar to signal completion. You can retrieve the passed uint32_t
value using .get_flag_value()
.
To handle timeouts, call .set_timeout(uint32_t)
to store the current time, then use .is_timeout()
to check if the timeout duration has elapsed.
case STATE::TX:
if (/* Transmission request successful */) {
step.set_timeout(100); // Set timeout
step.clear_flag(); // Wait for completion
step.next(STATE::TX_WAIT_COMP);
}
break;
case STATE::TX_WAIT_COMP:
if (step.is_timeout()) ...; // Timeout
if (step.is_flag_ready()) ...; // Flag was set
break;
...
// Transmission complete event
void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled) {
step.set_flag(ev.bStatus); // Set the flag
}
To continue using SM_SIMPLE
after waking from sleep, be sure to call .on_sleep(bool)
before going to sleep. If you pass false
, the state machine resets to state 0 upon waking; if true
, it resumes from the pre-sleep state.
void sleepNow() {
step.on_sleep(false); // Reset state machine
the_twelite.sleep(10000); // 10 sec
}
Source Code
Below is the source code for SM_SIMPLE
.
// very simple class to control state used in loop().
template <typename STATE>
class SM_SIMPLE {
uint32_t _u32_flag_value; // optional data when flag is set.
uint32_t _ms_start; // system time when start waiting.
uint32_t _ms_timeout; // timeout duration
STATE _step; // current state
STATE _step_prev; // previous state
bool_t _b_flag; // flag control.
public:
// init
void setup() { memset(this, 0, sizeof(SM_SIMPLE)); }
// call befoer sleeping (save state machine status)
void on_sleep(bool b_save_state = false) {
STATE save = _step;
setup();
if(b_save_state) _step = _step_prev = save;
}
// state control
void next(STATE next) { _step = next; } // set next state
STATE state() { return _step; } // state number
bool b_more_loop() { // if state is changed during the loop, set true
if (_step != _step_prev) { _step_prev = _step; return true; }
else return false;
}
// timeout control
void set_timeout(uint32_t timeout) {
_ms_start = millis();
_ms_timeout = timeout;
}
bool is_timeout() { return (millis() - _ms_start) >= _ms_timeout; }
// flag control
void clear_flag() { _b_flag = false; _u32_flag_value = 0; }
void set_flag(uint32_t u32_flag_value = 0) {
_b_flag = true;
_u32_flag_value = u32_flag_value; }
uint32_t get_flag_value() { return _u32_flag_value; }
bool is_flag_ready() { return _b_flag; }
};
- Contents may vary depending on the version.
- The source is located in the MWX library source folder under
SM_SIMPLE.hpp
.
1.1.5 - Callback Functions
The following callback functions are mandatory definitions.
setup()
loop()
Functions other than these will be linked as empty functions that do nothing if not defined.
Normal callback invocation order
init_coldboot()
↓ (TWENET internal processing: Initialization 1)
setup()
↓ (TWENET internal processing: Initialization 2)
begin() --- only once
↓
loop() <--+
↓ | Event processing, behavior processing
CPU DOZE -+
mwx_appcore.cpp
.Callback invocation order when waking up from sleep
the_twelite.sleep()
↓ sleeping...
init_warmboot()
↓ (TWENET internal processing: Initialization 3)
wakeup()
↓ (TWENET internal processing: Initialization 4)
loop() <--+
↓ | Event processing, behavior processing
CPU DOZE -+
mwx_appcore.cpp
.1.1.5.1 - setup()
TWENET initialization is also executed after the setup()
function finishes. Since many processes are designed to run after TWENET completes, please do not perform any operations other than initialization here.
The following points should be noted:
- You cannot execute sleep
the_twenet.sleep()
. If you want to sleep immediately after initialization, write the initial sleep process inside thebegin()
function. - The
delay()
function is replaced by the process described below. In this case, the parameterms
does not specify milliseconds.
static inline void delay(uint32_t ms) {
volatile uint32_t ct = ms * 4096;
while (ct > 0) {
--ct;
}
}
1.1.5.2 - begin()
loop()
function. Since TWENET initialization is complete, there is no need to consider constraints like those in setup()
.Mainly used in the following situations:
- Displaying the startup message
- Writing test code
- Transitioning to sleep immediately after startup
- Processing that is problematic in
setup()
(wireless packet processing, timer operation, etc.)
1.1.5.3 - loop()
In Act, most processing is written inside this loop.
1.1.5.4 - wakeup()
loop()
after waking from sleep, this function includes procedures for initialization after waking and branching processes according to the wake-up state.loop()
, you can execute sleep again within this function.1.1.5.5 - init_coldboot()
1.1.5.6 - init_warmboot()
1.1.5.7 - on_rx_packet()
void on_rx_packet(mwx::packet_rx& pkt, bool_t &b_handled)
When a wireless packet is received, this function is called from within the MWX library with the data stored in pkt
as packet_rx
. If this function is not defined in the application, a weak function that does nothing will be linked.
If true is set to b_handled
within this function, it notifies the MWX library that the received packet has been processed within the application. When marked as processed, unnecessary processing is suppressed (the processing of the_twelite.receiver
is not performed).
the_twelite.receiver
is not recommended.
Previously, processing using the_twelite.receiver
was intended to be written inside loop()
, but due to the queuing delay processing, packet loss can occur in principle, and the code tends to become complicated. Therefore, on_rx_packet()
was added.
1.1.5.8 - on_tx_comp()
void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled)
This function is called within the MWX library when the wireless packet transmission is finished, with data stored in ev
as packet_ev_tx
. If this function is not defined in the application, a do-nothing weak function is linked.
ev.u8CbId
is the ID at transmission, and ev.bStatus
is a flag indicating transmission success (1) or failure (0).
If true is set to b_handled
within this function, it informs the MWX library that the received packet has been processed within the application. When marked as processed, unnecessary processing is suppressed (event callback functions are not called for the_twelite.app
, .board
, or .settings
).
1.1.6 - Behavior
the_twelite
class object. Once registered, the behavior is integrated into TWENET and operates accordingly. User code can describe the application’s behavior via this mechanism. Unlike loop-based implementations, it enables defining interrupt handlers and callback functions from TWENET. Although it requires more code, this approach is suitable for constructing more complex applications.Class Definition (.hpp
)
A behavior is defined using a class structure like the one below.
class MY_APP_CLASS: MWX_APPDEFS_CRTP(MY_APP_CLASS)
{
public:
static const uint8_t TYPE_ID = 0x01;
// load common definition for handlers
#define __MWX_APP_CLASS_NAME MY_APP_CLASS
#include "_mwx_cbs_hpphead.hpp"
#undef __MWX_APP_CLASS_NAME
public:
// constructor
MY_APP_CLASS() {}
void _setup() {}
void _begin() {}
public:
// TWENET callback handler (mandate)
void loop() {}
void on_sleep(uint32_t & val) {}
void warmboot(uint32_t & val) {}
void wakeup(uint32_t & val) {}
void on_create(uint32_t& val) { _setup(); }
void on_begin(uint32_t& val) { _begin(); }
void on_message(uint32_t& val) { }
public:
void network_event(mwx::packet_ev_nwk& pEvNwk) {}
void receive(mwx::packet_rx& rx) {}
void transmit_complete(mwx::packet_ev_tx& evTx) {}
};
In the example above, a behavior class named MY_APP_CLASS
is defined. Several places require the name MY_APP_CLASS
.
class MY_APP_CLASS: MWX_APPDEFS_CRTP(MY_APP_CLASS)
Defines the class name and the base (parent) class. MWX_APPDEFS_CRTP()
is a macro.
#define __MWX_APP_CLASS_NAME MY_APP_CLASS
#include "_mwx_cbs_hpphead.hpp"
#undef __MWX_APP_CLASS_NAME
Includes the necessary definitions via #include
.
MY_APP_CLASS() {}
Defines the constructor.
Methods
loop()
The main loop function, serving the same role as the globally defined loop()
.
on_create()
on_create()
is called when the object is created (via the use<>()
method). The val
parameter is reserved for future extensions.
on_begin()
on_begin()
is called after setup()
completes. The val
parameter is reserved for future extensions.
on_sleep()
Called before entering sleep. The val
parameter is reserved for future extensions.
warmboot()
Called at the initial stage of wakeup from sleep. The val
parameter is reserved for future extensions.
At this point, peripherals are not yet initialized. You can check the cause of the sleep wakeup.
wakeup()
Called upon waking from sleep. The val
parameter is reserved for future extensions.
receive()
void receive(mwx::packet_rx& rx)
Called when a packet is received, with the received packet information passed as rx
.
transmit_complete()
void transmit_complete(mwx::packet_ev_tx& evTx)
Called when packet transmission is complete, with the transmission information passed as evTx
. evTx.u8CbId
is the ID used during transmission, and evTx.bStatus
is a flag indicating transmission success (1
) or failure (0
).
1.1.6.1 - PAL_AMB-behavior
This sample retrieves sensor values using the Ambient Sensor PAL.
- Demonstrates parent/child configuration using Behavior.
- Instead of using the Board Behavior functionality, sensor values are read directly using
Wire
. - The child device is implemented as a state machine.
Act Functionality
- Retrieves sensor values using the Ambient Sensor PAL.
- Uses sleep functionality to enable operation with coin cell batteries.
How to Use the Act
Preparing TWELITE
Role | Example |
---|---|
Parent | MONOSTICK BLUE or RED |
Child | BLUE PAL or RED PAL + Ambient Sensor PAL |
File Structure
- PAL_AMB-behavior.hpp: Defines only
setup()
. Reads DIP switches and acts as a parent if D1..D3 are ON; otherwise, acts as a child using the DIP switch as ID. - Parent/myAppBhvParent.hpp: Behavior class definition for the parent.
- Parent/myAppBhvParent.cpp: Implementation.
- Parent/myAppBhvParent-handlers.cpp: Handler implementations.
- Child/myAppBhvChild.hpp: Behavior class definition for the child.
- Child/myAppBhvChild.cpp: Implementation.
- Child/myAppBhvChild-handlers.cpp: Handler implementations.
The behavior name for the parent is <MY_APP_PARENT>
, and for the child it is <MY_APP_CHILD>
.
Initialization setup()
// now read DIP sw status can be read.
u8ID = (brd.get_DIPSW_BM() & 0x07);
// Register App Behavior (set differnt Application by DIP SW settings)
if (u8ID == 0) {
// put settings to the twelite main object.
the_twelite
<< TWENET::appid(APP_ID) // set application ID (identify network group)
<< TWENET::channel(CHANNEL) // set channel (pysical channel)
<< TWENET::rx_when_idle(); // open RX channel
the_twelite.app.use<MY_APP_PARENT>();
} else {
// put settings to the twelite main object.
the_twelite
<< TWENET::appid(APP_ID) // set application ID (identify network group)
<< TWENET::channel(CHANNEL); // set channel (pysical channel)
the_twelite.app.use<MY_APP_CHILD>();
}
If the DIP switch value is 0, the parent behavior <MY_APP_PARENT>
is registered; otherwise, the child behavior <MY_APP_CHILD>
is used.
Parent Behavior
The parent device acts as a receiver that does not sleep and outputs packet information to the serial port upon receiving packets from child devices.
MY_APP_PARENT::receive()
void MY_APP_PARENT::receive(mwx::packet_rx& rx) {
uint8_t msg[4];
uint32_t lumi;
uint16_t u16temp, u16humid;
// expand packet payload (shall match with sent packet data structure, see pack_bytes())
auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end(), msg);
// if PING packet, respond pong!
if (!strncmp((const char*)msg, (const char*)FOURCHARS, 4)) {
// get rest of data
expand_bytes(np, rx.get_payload().end(), lumi, u16temp, u16humid);
// print them
Serial << format("Packet(%x:%d/lq=%d/sq=%d): ",
rx.get_addr_src_long(), rx.get_addr_src_lid(),
rx.get_lqi(), rx.get_psRxDataApp()->u8Seq)
<< "temp=" << double(int16_t(u16temp)/100.0)
<< "C humid=" << double(int16_t(u16humid)/100.0)
<< "% lumi=" << int(lumi)
<< mwx::crlf << mwx::flush;
}
}
When the parent receives a packet, if the first four characters of the packet match (FOURCHARS
), the packet content is displayed.
MY_APP_PARENT::MWX_TICKTIMER_INT()
MWX_TICKTIMER_INT(uint32_t arg, uint8_t& handled) {
// blink LED
digitalWrite(PAL_AMB::PIN_LED,
((millis() >> 9) & 1) ? PIN_STATE::HIGH : PIN_STATE::LOW);
}
The interrupt handler for the parent blinks the LED.
MY_APP_PARENT::MWX_DIO_EVENT(PAL_AMB::PIN_BTN)
MWX_DIO_EVENT(PAL_AMB::PIN_BTN, uint32_t arg) {
Serial << "Button Pressed" << mwx::crlf;
static uint32_t u32tick_last;
uint32_t tick = millis();
if (tick - u32tick_last > 100) {
PEV_Process(E_ORDER_KICK, 0UL);
}
u32tick_last = tick;
}
When the button (5) on the PAL is pressed, an E_ORDER_KICK
event is issued to the state machine.
MY_APP_PARENT::MWX_STATE(E_MWX::STATE_0 .. 3)
The state machine described here serves as a reference for state transitions and does not have functional significance in the application. It handles state transitions triggered by the E_ORDER_KICK
event from the button and timeouts.
Child Behavior
The operation flow of the child device is similar to PAL_AMB-usenap
: it repeatedly performs the cycle of wake up → start sensor operation → short sleep → wake up → read sensor values → send via radio → wait for transmission completion → sleep.
MY_APP_CHILD::on_begin()
void _begin() {
// sleep immediately.
Serial << "..go into first sleep (1000ms)" << mwx::flush;
the_twelite.sleep(1000);
}
The _begin()
function called from on_begin()
performs the initial sleep.
(Note: It is also acceptable to write this process directly in on_begin()
instead of _begin()
.)
MY_APP_CHILD::wakeup()
void wakeup(uint32_t & val) {
Serial << mwx::crlf << "..wakeup" << mwx::crlf;
// init wire device.
Wire.begin();
// turn on LED
digitalWrite(PAL_AMB::PIN_LED, PIN_STATE::LOW);
// KICK it!
PEV_Process(E_ORDER_KICK, 0); // pass the event to state machine
}
This describes the wake-up process from sleep.
Here, the initial Wire.begin()
is executed. For subsequent wake-ups from sleep, this is redundant. This process may also be moved to on_begin()
.
MY_APP_CHILD::transmit_complete()
void transmit_complete(mwx::packet_ev_tx& txev) {
Serial << "..txcomp=" << int(txev.u8CbId) << mwx::crlf;
PEV_Process(E_ORDER_KICK, txev.u8CbId); // pass the event to state machine
}
Upon transmission completion, an E_ORDER_KICK
message is sent to the state machine.
MY_APP_CHILD::transmit_complete()
static const uint8_t STATE_IDLE = E_MWX::STATE_0;
static const uint8_t STATE_SENSOR = E_MWX::STATE_1;
static const uint8_t STATE_TX = E_MWX::STATE_2;
static const uint8_t STATE_SLEEP = E_MWX::STATE_3;
State names are defined here.
MY_APP_CHILD::shtc3_???()
MWX_APIRET MY_APP_CHILD::shtc3_start()
MWX_APIRET MY_APP_CHILD::shtc3_read()
These are sensor acquisition implementations for SHTC3. For details of commands sent, please refer to the SHTC3 datasheet.
MY_APP_CHILD::ltr308als_???()
MWX_APIRET MY_APP_CHILD::ltr308als_read()
MWX_APIRET MY_APP_CHILD::ltr308als_start()
static MWX_APIRET WireWriteAngGet(uint8_t addr, uint8_t cmd)
These are sensor acquisition implementations for LTR308ALS. For details of commands sent, please refer to the LTR308ALS datasheet.
WireWriteAndGet()
sends one byte cmd
to the device at addr
, then receives one byte and returns the value.
MY_APP_CHILD::STATE_IDLE (0)
MWX_STATE(MY_APP_CHILD::STATE_IDLE, uint32_t ev, uint32_t evarg) {
if (PEV_is_coldboot(ev,evarg)) {
Serial << "[STATE_IDLE:START_UP(" << int(evarg) << ")]" << mwx::crlf;
// then perform the first sleep at on_begin().
} else
if (PEV_is_warmboot(ev,evarg)) {
Serial << "[STATE_IDLE:START_UP(" << int(evarg) << ")]" << mwx::crlf;
PEV_SetState(STATE_SENSOR);
}
}
State 0 has a special meaning: it is the state immediately after startup or wake-up from sleep.
On cold boot, PEV_is_coldboot(ev,evarg)
returns true and this is called. Since on_begin()
immediately puts the device to sleep, no state transition code is included here. At this point, major initialization has not yet completed, so complex operations such as wireless packet transmission cannot be performed. To perform such operations, the first state transition is triggered by sending an event from on_begin()
and performing state transition accordingly.
On wake-up from sleep, PEV_is_warmboot(ev,evarg)
returns true on the first call. It calls PEV_SetState()
to transition to STATE_SENSOR
.
MY_APP_CHILD::STATE_SENSOR
MWX_STATE(MY_APP_CHILD::STATE_SENSOR, uint32_t ev, uint32_t evarg) {
if (ev == E_EVENT_NEW_STATE) {
Serial << "[STATE_SENSOR:NEW] Start Sensor." << mwx::crlf;
// start sensor capture
shtc3_start();
ltr308als_start();
// take a nap waiting finish of capture.
Serial << "..nap for 66ms" << mwx::crlf;
Serial.flush();
PEV_KeepStateOnWakeup(); // stay this state on waking up.
the_twelite.sleep(66, false, false, TWENET::SLEEP_WAKETIMER_SECONDARY);
} else
if (PEV_is_warmboot(ev,evarg)) {
// on wakeup, code starts here.
Serial << "[STATE_SENSOR:START_UP] Wakeup." << mwx::crlf;
PEV_SetState(STATE_TX);
}
}
When waking up from sleep and transitioning from STATE_IDLE
, the handler for STATE_SENSOR
is called with event E_EVENT_NEW_STATE
.
Here, sensor capture is started for SHTC3 and LTR308ALS. After a certain time, the sensors will be ready to provide data. This wait time is implemented as a sleep of 66 ms. Note that PEV_KeepStateOnWakeup()
is called before sleeping. This call ensures that upon wake-up, the state remains STATE_SENSOR
instead of returning to STATE_IDLE
.
After waking from the short sleep, PEV_is_warmboot(ev,evarg)
returns true on the first call, allowing wireless packet transmission and other operations. The state transitions to STATE_TX
.
MY_APP_CHILD::STATE_TX
MWX_STATE(MY_APP_CHILD::STATE_TX, uint32_t ev, uint32_t evarg)
static int u8txid;
if (ev == E_EVENT_NEW_STATE) {
Serial << "[STATE_TX:NEW]" << mwx::crlf;
u8txid = -1;
auto&& r1 = shtc3_read();
auto&& r2 = ltr308als_read();
Serial << "..shtc3 t=" << int(i16Temp) << ", h=" << int(i16Humd) << mwx::crlf;
Serial << "..ltr308als l=" << int(u32Lumi) << mwx::crlf;
if (r1 && r2) {
if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
Here, upon receiving the E_EVENT_NEW_STATE
event, sensor data is read and the wireless packet transmission procedure begins. For details on the transmission procedure, refer to other Act sample examples.
void transmit_complete(mwx::packet_ev_tx& txev) {
Serial << "..txcomp=" << int(txev.u8CbId) << mwx::crlf;
PEV_Process(E_ORDER_KICK, txev.u8CbId); // pass the event to state machine
}
// ↓ ↓ ↓ Send message
} else if (ev == E_ORDER_KICK && evarg == uint32_t(u8txid)) {
Serial << "[STATE_TX] SUCCESS TX(" << int(evarg) << ')' << mwx::crlf;
PEV_SetState(STATE_SLEEP);
}
The waiting for transmission completion is handled by waiting for the message sent from transmit_complete()
via PEV_Process()
. Upon receiving the message, the device goes to sleep by transitioning to STATE_SLEEP
.
if (PEV_u32Elaspsed_ms() > 100) {
// does not finish TX!
Serial << "[STATE_TX] FATAL, TX does not finish!" << mwx::crlf << mwx::flush;
the_twelite.reset_system();
}
Finally, a timeout process is implemented. This covers the case where the transmission completion message never arrives. PEV_u32Elaspsed_ms()
returns the elapsed time in milliseconds since entering this state. If the timeout occurs, the system resets with the_twelite.reset_system()
.
MY_APP_CHILD::STATE_SLEEP
MWX_STATE(MY_APP_CHILD::STATE_SLEEP, uint32_t ev, uint32_t evarg) {
if (ev == E_EVENT_NEW_STATE) {
Serial << "..sleep for 5000ms" << mwx::crlf;
pinMode(PAL_AMB::PIN_BTN, PIN_MODE::WAKE_FALLING_PULLUP);
digitalWrite(PAL_AMB::PIN_LED, PIN_STATE::HIGH);
Serial.flush();
the_twelite.sleep(5000); // regular sleep
}
}
The device goes to sleep. The sleep call is placed inside the conditional block that executes only once immediately after transitioning from the previous state (E_EVENT_NEW_STATE
). Since other events may be called before sleep, ensure that the_twelite.sleep()
is called exactly once here.
1.1.7 - Functions
1.1.7.1 - System Functions
1.1.7.1.1 - millis()
uint32_t millis()
The system time is updated by TickTimer interrupts.
1.1.7.1.2 - delay()
void delay(uint32_t ms)
Performs a delay for the period specified by ms
.
Time measurement is done using the TickTimer count. When a long delay is specified, the CPU clock is reduced during the polling process.
Every approximately 5 ms after calling delay()
, the internal watchdog process of the TWELITE microcontroller is executed.
※ For example, in the case of while(1) delay(1);
, the delay()
function does not exceed 5 ms, so the watchdog process is not invoked, resulting in a reset after a certain period.
Within the setup()
and wakeup()
functions, since the TickTimer is not yet running, delays are implemented using a while-loop. In this case, the discrepancy from the specified value may be significant. The loop counter is calibrated for 32 MHz. If the CPU clock is altered within these functions, errors proportional to that clock change will occur.
If a short delay such as 1 or 2 ms is specified as a parameter, the error may be relatively large.
1.1.7.1.3 - delayMicroseconds()
void delayMicroseconds(uint32_t microsec)
Performs a delay for the duration specified by microsec
.
Time measurement is done using the TickTimer count. When a long delay is specified, the CPU clock is reduced during polling.
Within the setup()
and wakeup()
functions, since the TickTimer is not yet running, delays are implemented using a while-loop. In this case, the discrepancy from the specified value may be significant. The loop counter is calibrated for 32 MHz. If the CPU clock is altered within these functions, errors proportional to the clock change will occur.
If a short duration such as 10 microseconds or less is specified as a parameter, the error may be relatively large.
1.1.7.1.4 - random()
uint32_t random(uint32_t maxval)
uint32_t random(uint32_t minval, uint32_t maxval)
The first function returns a value in the range 0..(maxval-1)
. Note that the value of maxval is not the maximum value itself.
The second function returns a value in the range minval..maxval-1
.
1.1.7.2 - General Purpose Digital IO
The following functions are used to operate General Purpose Digital IO (DIO).
pinMode()
digitalWrite()
digitalRead()
attachIntDio()
detachIntDio()
Constants
Pin Names and Numbers
Definition | Name |
---|---|
const uint8_t PIN_DIGITAL::DIO0 .. 19 | DIO pins 0 to 19 |
const uint8_t PIN_DIGITAL::DO0 .. 1 | DO pins 0,1 |
Pin Modes (DIO0..19)
The following enumerated values are handled by the type E_PIN_MODE
.
Definition | Pull-up | Name |
---|---|---|
PIN_MODE::INPUT | No | Input |
PIN_MODE::OUTPUT | No | Output |
PIN_MODE::INPUT_PULLUP | Yes | Input with Pull-up |
PIN_MODE::OUTPUT_INIT_HIGH | No | Output (initial state HIGH) |
PIN_MODE::OUTPUT_INIT_LOW | No | Output (initial state LOW) |
PIN_MODE::WAKE_FALLING | No | Input, wake pin, falling edge |
PIN_MODE::WAKE_RISING | No | Input, wake pin, rising edge |
PIN_MODE::WAKE_FALLING_PULLUP | Yes | Input, wake pin, falling edge with pull-up |
PIN_MODE::WAKE_RISING_PULLUP | Yes | Input, wake pin, rising edge with pull-up |
PIN_MODE::DISABLE_OUTPUT | Yes | Return to input state |
Pin Modes (DO0,1)
The following enumerated values are handled by the type E_PIN_MODE
.
Definition | Name |
---|---|
PIN_MODE::OUTPUT | Output |
PIN_MODE::OUTPUT_INIT_HIGH | Output (initial state HIGH) |
PIN_MODE::OUTPUT_INIT_LOW | Output (initial state LOW) |
PIN_MODE::DISABLE_OUTPUT | Stop output setting |
Pin States
The following enumerated values are handled by the type E_PIN_STATE
.
Definition | Value | Name |
---|---|---|
PIN_STATE::HIGH | 1 | HIGH level (=Vcc level) |
PIN_STATE::LOW | 0 | LOW level (=GND level) |
Pin Rising and Falling Edges
The following enumerated values are handled by the type E_PIN_INT_MODE
.
Definition | Name |
---|---|
PIN_INT_MODE::FALLING | Falling edge |
PIN_INT_MODE::RISING | Rising edge |
1.1.7.2.1 - pinMode()
void pinMode(uint8_t u8pin, E_PIN_MODE mode)
This function allows configuration of the states of DIO0 to DIO19 and DO0,1 pins. For details on the configuration values, refer to the enumerated values of E_PIN_MODE
in the DIO explanation and the DO explanation.
DO0 and DO1 are special-purpose pins and are generally used for other functions, but they can also be configured for output. However, these pins have hardware constraints, so caution is required when using them.
Both pins must be held at a HIGH level upon power-up. If the circuit configuration causes unstable voltage levels, it may result in the module failing to start.
1.1.7.2.2 - digitalWrite()
static inline void digitalWrite(uint8_t u8pin, E_PIN_STATE ulVal)
Beforehand, set the target pin as output using pinMode()
. The first parameter specifies the pin number to be set. The second parameter specifies either HIGH
or LOW
.
E_PIN_STATE
. A conversion operator from E_PIN_STATE
to int
is not defined, so direct input by numeric value is not allowed.1.1.7.2.3 - digitalRead()
static inline E_PIN_STATE digitalRead(uint8_t u8pin)
You can get the input value of a pin previously configured as input as LOW
or HIGH
.
E_PIN_STATE
type to int
type is not defined, direct assignment to a numeric type is not possible.1.1.7.2.4 - attachIntDio()
void attachIntDio(uint8_t u8pin, E_PIN_INT_MODE mode)
For a pin configured as input beforehand, the first parameter is the pin number for which you want to enable the interrupt, and the second parameter specifies the interrupt direction (rising edge, falling edge).
Example
Sets up an interrupt that triggers when the DIO5 pin changes from HIGH to LOW.
void setup() {
the_twelite.app.use<myAppClass>();
pinMode(PIN_DIGITAL::DIO5, PIN_MODE::INPUT_PULLUP);
attachIntDio(PIN_DIGITAL::DIO5, PIN_INT_MODE::FALLING);
}
void loop() {
;
}
myAppClass.hpp
class myAppClass: public mwx::BrdPal, MWX_APPDEFS_CRTP(myAppClasslMot)
{
};
Basic definition of the behavior myAppClass
. Details are omitted.
myAppClass.cpp
/*****************************************************************/
// MUST DEFINE CLASS NAME HERE
##define __MWX_APP_CLASS_NAME myAppClass
##include "_mwx_cbs_cpphead.hpp"
/*****************************************************************/
MWX_DIO_INT(PIN_DIGITAL::DIO5, uint32_t arg, uint8_t& handled) {
static uint8_t ct;
digitalWrite(PIN_DIGITAL::DIO12, (++ct & 1) ? HIGH : LOW);
handled = false; // if true, no further event.
}
MWX_DIO_EVENT(PIN_DIGITAL::DIO5, uint32_t arg) {
Serial << '*';
}
/*****************************************************************/
// common procedure (DO NOT REMOVE)
##include "_mwx_cbs_cpptail.cpp"
// MUST UNDEF CLASS NAME HERE
##undef __MWX_APP_CLASS_NAME
} // mwx
/*****************************************************************/
Interrupt handler description for the behavior myAppClass
. When an interrupt occurs on DIO5, it toggles the output setting of DIO12, and after the interrupt handler finishes, an event occurs that prints *
to the serial port Serial
.
1.1.7.2.5 - detachIntDio()
void detachIntDio(uint8_t u8pin)
1.1.7.2.6 - digitalReadBitmap()
uint32_t digitalReadBitmap()
Values are stored in order from the LSB side: DIO0 … DIO19.
Pins on the HIGH
side are set to 1, and pins on the LOW
side are set to 0.
1.1.7.3 - Utility Functions
1.1.7.3.1 - Printf Implementation
printf()
function in C.
int mwx_printf(const char* format, ...)
int mwx_snprintf(char* buffer, size_t count, const char* format, ...)
mwx_printf()
outputs formatted text to the Serial
object. It performs the same processing as Serial.printfmt()
.
mwx_snprintf()
performs snprintf
formatting to a buffer.
mwx::stream
.1.1.7.3.2 - pack_bits()
constexpr uint32_t pack_bits(...)
Parameters are specified as variadic arguments, each indicating a bit position (integer from 0 to 31). For example, pack_bits(1,3,6)
returns ((1UL<<1)|(1UL<<3)|(1UL<<6))
.
constexpr
enables compile-time evaluation when possible using constant expressions.Background
This function simplifies the notation in situations where values are referenced or set in various bitmaps such as IO port (DI, DO) states.
1.1.7.3.3 - collect_bits()
constexpr uint32_t collect_bits(uint32_t bm, ...)
From the value specified in the parameter bm
, this function extracts the values corresponding to the 0..31 bit positions specified by the subsequent variadic parameters. The extracted values are arranged in the order of the parameters and returned as a bitmap.
The bit ordering of the resulting bitmap places the first parameter in the highest bit and the last parameter at bit 0.
uint32_t b1 = 0x12; // (b00010010)
uint32_t b2 = collect_bits(b1, 4, 2, 1, 0);
// bit4->1, bit2->0, bit1->1, bit0->0
// b2=0x10 (b1010)
In this example, bits 4, 2, 1, and 0 of b1
are extracted, resulting in (1,0,1,0). This is interpreted as b1010, resulting in a calculated value of 0x10.
Background
This function simplifies code where values are referenced or set in various bitmaps, such as IO port (DI, DO) statuses.
1.1.7.3.4 - Byte array utils
Reading
Retrieve uint16_t
or uint32_t
values from a byte array interpreted as uint8_t
in big-endian order.
inline uint8_t G_BYTE(const uint8_t*& p) {
return *(p)++;
}
inline uint16_t G_WORD(const uint8_t*& p) {
uint32_t r = *p++;
r = (r << 8) + *p++;
return r;
}
inline uint32_t G_DWORD(const uint8_t*& p) {
uint32_t r = *p++;
r = (r << 8) + *p++;
r = (r << 8) + *p++;
r = (r << 8) + *p++;
return r;
}
p
is incremented by the number of bytes read.
Writing
Writes uint8_t
, uint16_t
, or uint32_t
values in big-endian order to the byte array pointed to by q
.
inline uint8_t& S_OCTET(uint8_t*& q, uint8_t c) {
*q++ = c;
return *q;
}
inline uint8_t& S_WORD(uint8_t*& q, uint16_t c) {
*(q) = ((c) >> 8) & 0xff; (q)++;
*(q) = ((c) & 0xff); (q)++;
return *q;
}
inline uint8_t& S_DWORD(uint8_t*& q, uint32_t c) {
*(q) = ((c) >> 24) & 0xff; (q)++;
*(q) = ((c) >> 16) & 0xff; (q)++;
*(q) = ((c) >> 8) & 0xff; (q)++;
*(q) = ((c) & 0xff); (q)++;
return *q;
}
q
is incremented by the number of bytes written.
Background
These utilities simplify operations during the construction and decomposition of data payloads in wireless packets.
You may also use the simplified pack_bytes()
and expand_bytes()
functions.
1.1.7.3.5 - pack_bytes()
uint8_t* pack_bytes(uint8_t* b, uint8_t* e, ...)
pack_bytes
takes container class begin()
, end()
iterators as parameters and writes the data specified by the following parameters into the container as a byte sequence.
The data types given as variadic arguments are as follows.
Data Type | Bytes | Description |
---|---|---|
uint8_t | 1 | |
uint16_t | 2 | Stored in big-endian order |
uint32_t | 4 | Stored in big-endian order |
uint8_t[N] | N | Fixed-length array of uint8_t |
std::pair<char*,N> | N | Pair of array and length for char* or uint8_t* arrays. Can be created with make_pair() . |
smplbuf_u8& pack_bytes(smplbuf_u8& c, ...)
pack_bytes
takes a container object as a parameter and writes the data specified by the following parameters into the container as a byte sequence. It appends to the end using the container’s .push_back()
method.
The data types given as variadic arguments are as follows.
Data Type | Bytes | Description |
---|---|---|
uint8_t | 1 | |
uint16_t | 2 | Stored in big-endian order |
uint32_t | 4 | Stored in big-endian order |
uint8_t[N] | N | Fixed-length array of uint8_t |
std::pair<char*,N> | N | Pair of array and length for char* or uint8_t* arrays. Can be created with make_pair() . |
smplbuf_u8? | .size() | smplbuf<> container of uint8_t type. Stores data of container length (.size() ). |
Example
auto&& rx = the_twelite.receiver.read();
smplbuf<uint8_t, 128> buf;
mwx::pack_bytes(buf
, uint8_t(rx.get_addr_src_lid()) // src addr (LID)
, uint8_t(0xCC) // cmd id (0xCC, fixed)
, uint8_t(rx.get_psRxDataApp()->u8Seq) // sequence number
, uint32_t(rx.get_addr_src_long()) // src addr (long)
, uint32_t(rx.get_addr_dst()) // dst addr
, uint8_t(rx.get_lqi()) // LQI
, uint16_t(rx.get_length()) // payload length
, rx.get_payload() // payload
);
In this example, attributes and payload of the received packet are re-stored into another buffer buf
.
Background
To simplify the description of byte arrays of type uint8_t
used for generating data payloads of wireless packets and extracting data.
auto&& rx = the_twelite.receiver.read();
uint8_t data[128];
data[0] = rx.get_addr_src_lid();
data[1] = 0xCC;
data[2] = rx.get_psRxDataApp()->u8Seq;
data[4] = rx.get_addr_src_long() & 0x000000FF;
data[5] = (rx.get_addr_src_long() & 0x0000FF00) >> 8;
data[6] = (rx.get_addr_src_long() & 0x00FF0000) >> 16;
data[7] = (rx.get_addr_src_long() & 0xFF000000) >> 24;
...
The above is the simplest description, but a byte array can be generated using Byte array utils as follows.
auto&& rx = the_twelite.receiver.read();
uint8_t data[128], *q = data;
S_OCTET(q, rx.get_addr_src_lid());
S_OCTET(q, 0xCC);
S_OCTET(q, rx.get_psRxDataApp()->u8Seq);
S_DWORD(q, rx.get_addr_src_long());
S_DWORD(q, rx.get_addr_dst());
S_OCTET(q, rx.get_lqi());
S_WORD(q, rx.get_length());
for (auto x : rx.get_payload()) {
S_OCTET(q, x);
}
1.1.7.3.6 - expand-bytes()
const uint8_t* expand_bytes(
const uint8_t* b, const uint8_t* e, ...)
expand_bytes()
takes a combination of iterators of type uint8_t*
as parameters. These specify the beginning of the target to be parsed and the iterator just past the end. If parsing reaches the position of e
, it results in an error and returns nullptr
.
If there is no error in expansion, it returns the iterator for the next reading.
The variable parameters should be specified as follows:
Number of bytes | Data length | Explanation |
---|---|---|
uint8_t | 1 | |
uint16_t | 2 | Expanded as big-endian order |
uint32_t | 4 | Expanded as big-endian order |
uint8_t[N] | N | Fixed-length array of uint8_t |
std::pair<char*,N> | N | A pair of array and array length N of type char* or uint8_t* created by make_pair() |
Example
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{};
auto&& np =
expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
, make_pair((uint8_t*)fourchars, 4)
);
// read rest of payload
uint8_t u8DI_BM_remote = 0xff;
uint16_t au16AI_remote[5];
expand_bytes(np, rx.get_payload().end()
, u8DI_BM_remote
, au16AI_remote[0]
, au16AI_remote[1]
, au16AI_remote[2]
, au16AI_remote[3]
, au16AI_remote[4]
);
In this example, first a 4-byte string is read. Here, make_pair()
is used to explicitly read 4 bytes of data.
Using the returned iterator np
as a base, the next data is read. The next data consists of a uint8_t
type followed by five uint16_t
types.
Background
To simplify the description of byte arrays of type uint8_t
used for generating and extracting data payloads of wireless packets.
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{};
uint8_t u8DI_BM_remote = 0xff;
uint16_t au16AI_remote[5];
uint8_t *p = rx.get_payload().begin();
fourchars[0] = p[0];
fourchars[1] = p[1];
fourchars[2] = p[2];
fourchars[3] = p[3];
fourchars[4] = 0;
p += 4;
u8DI_BM_remote = (p[0] << 8) + p[1]; p+=2;
au16AI_remote[0] = (p[0] << 8) + p[1]; p+=2;
...
The above is the simplest description, but you can read from byte arrays using Byte array utils as follows:
auto&& rx = the_twelite.receiver.read();
char fourchars[5]{};
uint8_t u8DI_BM_remote = 0xff;
uint16_t au16AI_remote[5];
uint8_t *p = rx.get_payload().begin();
fourchars[0] = G_BYTE(p);
fourchars[1] = G_BYTE(p);
fourchars[2] = G_BYTE(p);
fourchars[3] = G_BYTE(p);
fourchars[4] = 0;
u8DI_BM_remote = G_WORD(p);
au16AI_remote[0] = G_WORD(p);
...
1.1.7.3.7 - CRC8, XOR, LRC
uint8_t CRC8_u8Calc(uint8_t *pu8Data, uint8_t size, uint8_t init=0)
uint8_t CRC8_u8CalcU32(uint32_t u32c, uint8_t init=0)
uint8_t CRC8_u8CalcU16(uint16_t u16c, uint8_t init=0)
uint8_t XOR_u8Calc(uint8_t *pu8Data, uint8_t size)
uint8_t LRC_u8Calc(uint8_t* pu8Data, uint8_t size)
Performs calculations for CRC8, XOR, and LRC (used in ASCII format).
CRC8_u8CalcU16()
and CRC8_u8CalcU32()
compute the CRC8 for u16c
and u32c
assuming big-endian order.
X^8+X^5+X^4+1
(polynomial value 0x31), which is sometimes referred to as CRC8-CCITT or CRC8-Maxim.Background
These functions were added as library procedures because they are used for validating wireless packet data sequences, ASCII format checksums (LRC), and various sensor data checks.
1.1.7.3.8 - div10(), div100(), div1000()
struct div_result_i32 {
int32_t quo; // quotient
int16_t rem; // remainder
uint8_t b_neg; // true if negative
uint8_t digits_rem; // digits of remainder
};
div_result_i32 div10(int32_t val);
div_result_i32 div100(int32_t val);
div_result_i32 div1000(int32_t val);
In some cases, sensor values multiplied by 100 are passed as uint16_t
type, but on microcontrollers without division circuits, calculation processing takes considerable time. Therefore, calculations are performed using approximate calculations and corrections with addition, subtraction, multiplication, and bit shifts.
Pass the value to be calculated in val
, the variable to store the remainder in rem
, and the variable to store the sign in neg
.
The return value is the quotient (always positive), rem
contains the remainder (always positive), and neg
stores true
if negative.
Due to algorithm constraints (digit overflow), the calculable value range is limited for div100()
and div1000()
. div100()
supports values from -99999 to 99999, and div1000()
supports values from -999999 to 999999.
Approximate formula to obtain the quotient
div100()
int dv = val * 1311 >> 17;
div1000()
int dv = val * 131 >> 17;
Example usage
auto d1 = div100(sns_val.u16temp_object);
auto d2 = div100(sns_val.u16temp_object);
Serial
<< crlf << format("..Object = %c%2d.%02d"
, d1.b_neg ? '-' : '+', d1.quo, d1.rem)
<< format(" Ambient = %c%2d.%02d"
, d2.b_neg ? '-' : '+', d2.quo, d2.rem);
Calculation speed
About one-tenth of the time.
Output of results
// Conversion options
struct DIVFMT {
static const int STD = 0; // displays with minimal digits (no padding, no positive sign)
static const int PAD_ZERO = 1; // set padding character as '0' instead of ' '.
static const int SIGN_PLUS = 2; // put '+' sign if value is positive or 0.
static const int PAD_ZERO_SIGN_PLUS = 3; // PAD_ZERO & SIGN_PLUS
static const int SIGN_SPACE = 4; // put ' ' sign if value is positive or 0.
static const int PAD_ZERO_SIGN_SPACE = 5; // PAD_ZERO & SIGN_SPACE
};
// Class to store string conversion results
class _div_chars {
...
const char* begin() const {...}
const char* end() const {...}
const char* c_str() const { return begin(); }
operator const char*() const { return begin(); }
};
// format() method
_div_chars div_result_i32::format(
int dig_quo = 0, uint32_t opt = DIVFMT::STD) const;
// Implementation of interface to Serial
template <class D> class stream {
...
inline D& operator << (const mwx::_div_chars&& divc);
inline D& operator << (const mwx::div_result_i32&&);
inline D& operator << (const mwx::div_result_i32&);
};
The div_result_i32
class that stores the division result has a format()
method to obtain a _div_chars
class object. The _div_chars
class object contains a string buffer and provides methods to access the string buffer as const char*
. Also, the <<
operator for the Serial
object is implemented.
The first parameter dig_quo
of the format()
method specifies the number of output digits (excluding the sign). If the output digits are insufficient (below), it is filled with spaces or 0
. The second parameter opt
specifies the format.
opt parameter | Description |
---|---|
DIVFMT::STD | Standard output, fills insufficient digits with spaces, and adds - only for negative values. |
DIVFMT::PAD_ZERO | Fills insufficient digits with 0 . |
DIVFMT::SIGN_PLUS | Adds + sign for positive values as well. |
DIVFMT::PAD_ZERO_SIGN_PLUS | Fills insufficient digits with 0 and adds + sign for positive values. |
DIVFMT::SIGN_SPACE | Adds a space sign instead of + for positive values. |
DIVFMT::PAD_ZERO_SIGN_SPACE | Fills insufficient digits with 0 and adds a space sign instead of + for positive values. |
Example
//// Direct output from div_result_i32 object
Serial << div100(-1234) << crlf;
// Result: -12.34
//// Output with 3 digits
Serial << div100(3456).format(3, DIVFMT::PAD_ZERO_SIGN_PLUE) << crlf;
// Result: +034.56
//// Use c_str() to get const char*
char str1[128];
auto x = div100(-5678);
mwx_snprintf(str1, 16, "VAL=%s", x.format.c_str()); // const char*
Serial << str1;
// Result: VAL=-56.78
Background
In TWELITE BLUE/RED, division is a costly operation, so a division algorithm with limited purposes was added.
Within the library, some sensor values such as temperature and humidity are represented using values multiplied by 100 (e.g., 25.12℃ as 2512), so a simple procedure to obtain the quotient and remainder when divided by 100 was defined.
dev_result_i32::format()
is provided to avoid complexity when formatting output.
1.1.7.3.9 - Scale utils
x*1000/255
) is replaced with multiplication and bit shifts for approximate calculation.
static inline uint8_t scale_1000_to_127u8(uint16_t x)
static inline uint16_t scale_127u8_to_1000(uint8_t x)
static inline uint8_t scale_1000_to_255u8(uint16_t x)
static inline uint16_t scale_255u8_to_1000(uint8_t x)
static inline uint8_t scale_1000_to_256u8(uint16_t x)
static inline uint16_t scale_256u16_to_1000(uint16_t x)
scale_1000_to_127u8()
Scales 0..1000 to 0..127. Uses (16646*x+65000)>>17
for approximate calculation.
scale_127u8_to_1000()
Scales 0..127 to 0..1000. Uses (2064000UL*x+131072)>>18
for approximate calculation.
scale_1000_to_255u8()
Scales 0..1000 to 0..255. Uses (33423*x+65000)>>17
for approximate calculation.
scale_255u8_to_1000()
Scales 0..255 to 0..1000. Uses (1028000UL*uint32_t(x)+131072)>>18
for approximate calculation.
scale_1000_to_256u8()
Scales 0..1000 to 0..256. Uses (33554*x+66000) >> 17
for approximate calculation.
Note: For x=999,1000 the calculated value becomes 256, but returns 255 as the range of uint8_t
.
scale_256u16_to_1000()
Scales 0..256 to 0..1000. Uses (1028000UL*uint32_t(x)+131072)>>18
for approximate calculation.
Background
Values to be set in hardware are often based on binary such as 0..255, while numbers handled in user applications are easier to manage when based on decimal such as 0..1000. These scale conversions define formulas that do not use division.
1.1.7.3.10 - pnew()
template <class T, class... Args>
T* pnew(T& obj, Args&&... args) {
return (T*)new ((void*)&obj) T(std::forward<Args&&>(args)...);
}
For example, it can be used as follows. You can also pass constructor arguments.
class my_class {
int _a;
public:
my_class(int a = -1) : _a(a) {}
};
my_class obj_1; // This constructor is not called!
my_class obj_2; // This constructor is not called!
void setup() {
mwx::pnew(obj_1); // Equivalent to my_class obj_1;
mwx::pnew(obj_2, 2); // Equivalent to my_class obj_2(2);
...
}
Background
Due to compiler constraints, constructors of global objects are not called. One method to initialize them is using placement new. However, the placement new syntax can appear verbose.
Another method is to use std::unique_ptr
(or eastl::unique_ptr
).
std::unique_ptr<my_class> obj_3;
void setup() {
obj_3.reset(new my_class(3));
// On TWELITE microcontrollers, `new` can only allocate once and `delete` cannot be used,
// so in practice it is equivalent to a global object.
}
1.1.8 - External Libraries
- EASTL - EASTL is a C++ standard library by Electronic Arts. It provides containers that operate with fixed-length memory, making it well-suited for use in embedded microcontrollers. The TWELITE STAGE SDK can be built with it without any special configuration.
1.1.8.1 - EASTL
This library makes EASTL available within TWENET.
Below is an example of using a fixed-length array and applying a sorting algorithm.
The features of EASTL are as follows.
- Containers with fixed memory allocation (
fixed_
): You can declare containers with a fixed number of elements without dynamic allocation. If declared globally, the memory area is allocated at compile time; if declared locally, it is allocated on the stack and available within that scope. - Intrusive containers: While regular containers can store arbitrary data structures, intrusive containers require your data structure to inherit from a special base class, which maintains link information for the container. Each element is dedicated to that container, but for lists and map structures, this is highly memory efficient. (Reference: Intrusive and non-intrusive containers)
The development motivation and more are described in a 2007 article: EASTL (open-std.org). (Related articles: A glimpse into the state of game software development through EASTL Part 1, Part 2)
Usage in TWENET
Please note the following.
We have not comprehensively tested the operation of this library. Please conduct your own operation verification. We are also unable to respond to inquiries about how to use EASTL. Please refer to resources and source code provided by the distributor.
- Uses EASTL 3.07 (2018/1/31), the last version that can be compiled with C++11.
- The following libraries are not included:
test/packages/EAAssert
,source/assert.cpp
test/packages/EATest
test/packages/EAThread
,source/thread_support.cpp
- Test code in
test/source
has not been ported. - For sprintf-related functions, only
EA::StdC::Vsnprintf(char8_t*, ...)
is resolved by callingvsnprintf_()
in the printf.h library.
How to Embed and Compile
You can use EASTL when writing Act scripts.
The required include paths and library additions for the TWELITE development environment are already set. Please include the library headers in your code as needed.
#include <TWELITE>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
void setup() {
tstr128 s1;
s1 = "Hello World";
Serial << s1.c_str();
}
void loop() {
;
}
Embedding Details
Compiling the library and setting the include paths have already been done under the MWSDK/TWENET directories, but the internal settings are described below.
- Compile the code in EASTL/source into a library archive (
libEASTL.a
). This library must be referenced at link time. - Add the following include paths at compile time.
If you set $(PATH_EASTL)
as the EASTL directory, the include paths are as follows:
-I$(PATH_EASTL)/include
-I$(PATH_EASTL)/test/packages/EAAssert/include
-I$(PATH_EASTL)/test/packages/EABase/include/Common
-I$(PATH_EASTL)/test/packages/EAMain/include
-I$(PATH_EASTL)/test/packages/EAStdC/include
-I$(PATH_EASTL)/test/packages/EATest/include
-I$(PATH_EASTL)/test/packages/EAThread/include
Coding Notes
About std::
and eastl::
The MWX library itself uses the standard library in the std::
namespace.
The standard library (std::
) and EASTL (eastl::
) both define items with the same names and functions. Sometimes they can coexist, but sometimes using both will cause errors. In general, use the definitions within EASTL for EASTL objects (for example, storing an eastl::fixed_string
in a std::unique_ptr
will result in a compiler error).
Also, be careful about name collisions when using statements like using namespace std;
.
Global Object Initialization 1 (Placement new)
In TWENET development, due to compiler restrictions, constructors for globally declared objects are not executed. The memory area for a globally declared object is only zero-initialized. If you run the code as is, it will usually hang due to null pointer access.
To initialize such objects, use placement new.
#include <TWELITE>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
tstr128 g_str1; // constructor is NOT called! needs to be initialized before use.
void setup() {
(void) new ((void*)&g_str1) tstr128("Hello World");
Serial << g_str1.c_str();
}
The placement new code can look a bit messy, so a helper function mwx::pnew()
is provided. The previous example can be rewritten as follows:
(void) new ((void*)&g_str1) tstr128("Hello World");
// ↓
mwx::pnew(g_str1, "Hello World");
Note: The second and subsequent arguments are variable and are passed directly to the constructor.
Global Object Initialization 2 (unique_ptr
)
Another way to initialize global objects is to use unique_ptr
(std::unique_ptr reference). unique_ptr
exists in both std::
and eastl::
, but for EASTL classes, use the eastl::
version.
Call .reset()
at the timing of initialization as shown below.
#include <TWELITE>
#include <EASTL/unique_ptr.h>
#include <EASTL/fixed_string.h>
using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;
eastl::unique_ptr<tstr128> uq_str1;
void setup() {
uq_str1.reset(new tstr128("Hello World"));
if (uq_str1) { // true: object is stored.
Serial << uq_str1->c_str();
}
}
About intrusive
Containers
The following is an example of defining an element for intrusive_list
. The only member is int mX
.
struct IntNode : public eastl::intrusive_list_node {
int mX;
IntNode(int x = 0) : mX(x) { }
// no need to call super class's constructor eastl::intrusive_list_node()
};
inline bool operator<(const IntNode& a, const IntNode& b) { return a.mX < b.mX; }
inline bool operator>(const IntNode& a, const IntNode& b) { return a.mX > b.mX; }
Elements for intrusive_list
must always inherit from intrusive_list_node
as a base class. The base class includes link pointers to maintain the list. Here, comparison operators are also defined for use with sort
and similar algorithms.
using tiList = intrusive_list<IntNode>;
void setup() {
IntNode nodeA(5);
IntNode nodeB(1);
IntNode nodeC(9);
IntNode nodeD(2);
IntNode nodeE(4);
tiList l; // intrusive_list body
l.push_front(nodeA); // forming list structure
// by updating link info in intrusive_list_node.
l.push_front(nodeB);
l.push_front(nodeC);
l.push_front(nodeD);
l.push_front(nodeE);
l.sort(); // sort, using < operator
l.sort(eastl::greater<tilist::value_type>()); // sort, using > operator
}
References
- EA Standard Template Library — Note: the library included in TWENET is for EASTL 3.07, so it may not include elements implemented or changed in later versions.
- cpprefjp - C++ Japanese Reference — While it’s in Japanese, the STL explanations are useful.
About This Sample
The EASTL license is as follows.
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
/*
Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
Sample code applies MWSLA-1J/E.
Code Examples
fixed_vector
An array with a fixed maximum length (i.e., it does not expand). (*Note: mwx::smplbuf
is also a fixed-length array, but it is specialized for some internal processing in the MWX library.)
#include <TWELITE>
#include <EASTL/fixed_vector.h>
#include <EASTL/sort.h>
using tvct = eastl::fixed_vector<uint16_t, 64, false>;
tvct v;
void setup() {
mwx::pnew(v); // initialize
v = { 3, 1, 2 ,4 }; // set initial list.
// push and pop
v.pop_back(); // 3, 1, 2
v.push_back(5); // 3, 1, 2, 5
// sort
eastl::sort(v.begin(), v.end(), eastl::less<tvct::value_type>());
// 1, 2, 3, 5
// display all
for (auto x : v) { Serial << format(" %d", x); }
Serial << crlf;
// using [] operator
for (int i = 0; i < v.size(); i++) { Serial << format(" %d", v[i]); }
}
The template arguments for fixed_vector
are: first is the type, second is the maximum number of elements, and third should be false. Array operations are similar to std::vector
, such as .push_back()
, .pop_back()
, and the []
operator.
You can also apply sorting algorithms. In the example above, eastl::sort
is used in ascending order with eastl::less
.
fixed_list
A list structure with a fixed maximum number of elements (see also intrusive_list
).
#include <TWELITE>
#include <EASTL/fixed_list.h>
#include <EASTL/sort.h>
using tdata = eastl::pair<uint8_t, void (*)(uint8_t)>; // element data type
using tlst = eastl::fixed_list<tdata, 3, false>; // fixed_list with 3 elements.
tlst l; // list object
void setup() {
mwx::pnew(l); // initialize (call constructor)
// add
if (!l.full()) l.insert(l.begin(), eastl::make_pair('A', [](uint8_t v){ Serial << format("(1:%c)", v); } ));
if (!l.full()) l.insert(l.begin(), eastl::make_pair('B', [](uint8_t v){ Serial << format("(2:%c)", v); } ));
if (!l.full()) l.insert(l.begin(), eastl::make_pair('C', [](uint8_t v){ Serial << format("(3:%c)", v); } ));
if (!l.full()) l.insert(l.begin(), eastl::make_pair('D', [](uint8_t v){ Serial << format("(4:%c)", v); } )); // fails
Serial << crlf << "init: "; for(auto &x: l) x.second(x.first);
// find & erase
auto p = eastl::find_if(l.begin(), l.end(), [](tdata& x) { return (x.first == 'B'); } );
if (p != l.end()) l.erase(p);
Serial << crlf << "find&erase: "; for(auto &x: l) x.second(x.first);
// append
if (!l.full()) l.insert(l.end(), eastl::make_pair('D', [](uint8_t v){ Serial << format("(4:%c)", v); } ));
Serial << crlf << "append: "; for(auto &x: l) x.second(x.first);
// sort
eastl::sort(l.begin(), l.end(), eastl::less<tlst::value_type>());
Serial << crlf << "sort:"; for(auto &x: l) x.second(x.first);
// sort reverse
eastl::sort(l.begin(), l.end(), eastl::greater<tlst::value_type>());
Serial << crlf << "sort(rev):"; for(auto &x: l) x.second(x.first);
}
The template arguments for fixed_list
are: first is the type, second is the maximum number of elements, and third should be false. List operations are similar to std::list
, such as .insert()
, .erase()
, etc.
In the above code, the list stores elements of eastl::pair
, with the first being a uint8_t
integer and the second being a function pointer void (*)(uint8_t)
. Lambdas are used directly in the code. The line x.second(x.first);
means calling the function stored in second with the value of first.
You can search for elements using eastl::find_if
and sort using bubble_sort
.
intrusive_list
While regular lists can hold arbitrary data structures as elements, intrusive_list
attaches specific data to elements and uses that data to build the structure.
In the following example, the element type for the intrusive_list must inherit from eastl::intrusive_list_node
. eastl::intrusive_list_node
is an extension that allows storing pointers to previous and next elements.
#include <TWELITE>
#include <EASTL/fixed_vector.h>
#include <EASTL/intrusive_list.h>
#include <EASTL/unique_ptr.h>
// list element of intrusive_list.
struct IntNode : public eastl::intrusive_list_node {
int mX;
IntNode(int x = 0) : mX(x) { }
};
inline bool operator>(const IntNode& a, const IntNode& b) { return a.mX > b.mX; } // for sort
using tpool = eastl::fixed_vector<IntNode, 16, false>;
using tlst = eastl::intrusive_list<IntNode>;
tpool pool; // instance pool.
tlst l; // list object
void setup() {
mwx::pnew(pool); // prepare instances
mwx::pnew(l); // initialize (call constructor)
pool.resize(5); // create 5 instances in pool
// insert an IntNode element into List.
int i = 0;
pool[i].mX = 5; l.push_front(pool[i]); i++;
pool[i].mX = 1; l.push_front(pool[i]); i++;
pool[i].mX = 2; l.push_front(pool[i]); i++;
pool[i].mX = 4; l.push_front(pool[i]); i++;
pool[i].mX = 3; l.push_front(pool[i]); i++;
Serial << crlf << "init: ";
for(auto& x : l) { Serial << format(" %d", x.mX); }
l.remove(pool[2]);
Serial << crlf << "remove: ";
for(auto& x : l) { Serial << format(" %d", x.mX); }
l.sort(eastl::greater<tlst::value_type>());
Serial << crlf << "sort: ";
for(auto& x : l) { Serial << format(" %d", x.mX); }
}
In this example, eastl::fixed_vector<>
is used to allocate the necessary number of IntNode
elements; fixed_vector
itself is not required for the list. Five elements are given test values to build the intrusive_list
. The example calls l.push_front()
to add elements one by one to the list. In reality, instead of storing elements, the pointers in each IntNode
are rewired.
Sorting is done by calling the member function l.sort()
.
ring_buffer
The ring buffer ring_buffer
is constructed in combination with another container (in this example, fixed_vector
).
#include <TWELITE>
#include <EASTL/fixed_vector.h>
#include <EASTL/bonus/ring_buffer.h>
const size_t N_RING_ELE = 4; // element max for RING BUFFER.
using tvec = eastl::fixed_vector<uint8_t, N_RING_ELE + 1, false>; // One extra element is required.
using tring = eastl::ring_buffer<uint8_t, tvec>;
tring rb;
void setup() {
mwx::pnew(rb, N_RING_ELE);
rb.push_front(5);
rb.push_front(1);
rb.push_front(4);
rb.push_front(2);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
rb.push_front(3);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
rb.push_front(8);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
rb.push_front(9);
Serial << crlf; for (auto x : rb) Serial << format(" %d", x);
Serial << crlf << format("back=%d", rb.back()) << crlf;
rb.pop_back();
for (auto x : rb) Serial << format(" %d", x);
}
The definition of ring_buffer
is a combination of the element type and its container type. The element type should have one extra element.
In the example above, .push_front()
inserts an element at the front. If it overflows, the oldest element at the back is dropped. Use .back()
to get the oldest element, and pop_back()
to remove it.
intrusive_hash_map
A map structure is a data structure that holds key-value pairs and is designed to efficiently extract elements by key. intrusive_hash_map
is implemented using the intrusive structure and hash values. The definition is a bit complicated, but memory usage is minimized.
As with intrusive_list
, you must define your own element type IntNode
inheriting from eastl::intrusive_hash_node_key<ElementType>
. You also need to define the maximum number of hash buckets (N_BUCKET_CT
). This value should be a suitable prime number according to the expected number of elements.
#include <TWELITE>
#include <EASTL/internal/intrusive_hashtable.h>
#include <EASTL/intrusive_hash_map.h>
static const unsigned N_BUCKET_CT = 7;
// intrusive element type
struct IntNode : public eastl::intrusive_hash_node_key<uint8_t> {
using SUP = intrusive_hash_node_key;
void (*m_func)(); // member variable is func pointer.
IntNode(uint8_t key = 0) { SUP::mKey = key; } // key will be passed by the constructor.
};
// intrusive map type
using tmap = eastl::intrusive_hash_map<uint8_t, IntNode, N_BUCKET_CT>;
tmap mp;
IntNode nd_a, nd_b, nd_c, nd_d;
void setup() {
mwx::pnew(mp); // initialize (call constructor)
mwx::pnew(nd_a, 'A')->m_func = []() { Serial << "FuncA"; };
mwx::pnew(nd_b, 'B')->m_func = []() { Serial << "FuncB"; };
mwx::pnew(nd_c, 'C')->m_func = []() { Serial << "FuncC"; };
mwx::pnew(nd_d, 'D')->m_func = []() { Serial << "FuncD"; };
mp.insert(nd_a);
mp.insert(nd_b);
mp.insert(nd_c);
mp.insert(nd_d);
}
void loop() {
int c = Serial.read();
if(c != -1) {
Serial << crlf << '[' << uint8_t(c) << ']';
auto&& it = mp.find(uint8_t(c));
if (it != mp.end()) it->m_func();
}
}
In the example above, the map key is a uint8_t
character, and the map value is a function pointer. In loop()
, a function is executed according to the key input.
First, the table and elements are defined as global objects, so in setup()
you call mwx::pnew()
to initialize the data elements (nd_a, nd_b, nd_c, nd_d
) and the hash map (mp
). The return value of mwx::pnew()
is a pointer to the constructed object, so after initialization, you can directly assign a value (lambda) to a member variable.
Once the elements (nd_a, nd_b, nd_c, nd_d
) are initialized and their values set, insert them into the map with mp.insert(nd_a)
and so on.
In loop()
, every time a character is input from serial, a search is performed on the hash map. Search is done with the mp.find()
method, which returns an iterator; if the search fails, it returns mp.end()
. If the search succeeds, you can access the found element with (*it)
.
intrusive_hash_multimap
is a multimap that allows duplicate values. Usage is almost the same as a hash map, but when searching you use .equal_range()
, and you handle a pair of iterators.
using tmap = eastl::intrusive_hash_multimap<uint8_t, IntNode, N_BUCKET_CT>;
...
// find elements by key `c'
auto ip = mp.equal_range(uint8_t(c));
for(auto&& it = ip.first; it != ip.second; it++) {
it->m_func();
}
1.1.9 - Board Behavior (BRD)
- Definition of constants (e.g., pin numbers)
- Hardware initialization
- Handling sensors and similar peripherals
1.1.9.1 - <BRD_APPTWELITE>
This is a board behavior assuming the same wiring as the “Extremely Simple! Standard App (App_Twelite).” It defines constants and provides functions for reading M1–M3 and BPS pins.
Constants
The following constants are defined:
static const uint8_t PIN_DI1 = mwx::PIN_DIGITAL::DIO12;
static const uint8_t PIN_DI2 = mwx::PIN_DIGITAL::DIO13;
static const uint8_t PIN_DI3 = mwx::PIN_DIGITAL::DIO11;
static const uint8_t PIN_DI4 = mwx::PIN_DIGITAL::DIO16;
static const uint8_t PIN_DO1 = mwx::PIN_DIGITAL::DIO18;
static const uint8_t PIN_DO2 = mwx::PIN_DIGITAL::DIO19;
static const uint8_t PIN_DO3 = mwx::PIN_DIGITAL::DIO4;
static const uint8_t PIN_DO4 = mwx::PIN_DIGITAL::DIO9;
static const uint8_t PIN_M1 = mwx::PIN_DIGITAL::DIO10;
static const uint8_t PIN_M2 = mwx::PIN_DIGITAL::DIO2;
static const uint8_t PIN_M3 = mwx::PIN_DIGITAL::DIO3;
static const uint8_t PIN_BPS = mwx::PIN_DIGITAL::DIO17;
static const uint8_t PIN_AI1 = mwx::PIN_ANALOGUE::A1;
static const uint8_t PIN_AI2 = mwx::PIN_ANALOGUE::A3;
static const uint8_t PIN_AI3 = mwx::PIN_ANALOGUE::A2;
static const uint8_t PIN_AI4 = mwx::PIN_ANALOGUE::A4;
You can access them like BRD_APPTWELITE::PIN_DI1
.
Methods
Methods are provided to read the values of DIP SW (M1, M2, M3, BPS) pins.
inline uint8_t get_M1()
inline uint8_t get_M2()
inline uint8_t get_M3()
inline uint8_t get_BPS()
inline uint8_t get_DIPSW_BM()
The return value is not HIGH or LOW: 0
means the switch is not set (HIGH side), 1
means it is set (LOW side).
get_DIPSW_BM()
returns the values of M1, M2, M3, and BPS pins in order from bit 0.
1.1.9.2 - PAL Common Definitions
Constants
The following constants are defined:
static const uint8_t PIN_BTN = 12; // button (as SET)
static const uint8_t PIN_LED = 5; // LED
static const uint8_t PIN_WDT = 13; // WDT (shall tick every 60sec)
static const uint8_t PIN_D1 = 1; // DIP SW1
static const uint8_t PIN_D2 = 2; // DIP SW2
static const uint8_t PIN_D3 = 3; // DIP SW3
static const uint8_t PIN_D4 = 4; // DIP SW4
static const uint8_t PIN_SNS_EN = 16;
static const uint8_t PIN_SNS_INT = 17;
These can be accessed like PAL_AMB::PIN_BTN
.
Hardware Initialization
pinMode(PIN_BTN, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT_INIT_HIGH);
pinMode(PIN_WDT, OUTPUT_INIT_HIGH);
pinMode(PIN_D1, INPUT_PULLUP);
pinMode(PIN_D2, INPUT_PULLUP);
pinMode(PIN_D3, INPUT_PULLUP);
pinMode(PIN_D4, INPUT_PULLUP);
Pins are initialized as shown in the code above.
Watchdog Timer
The external watchdog timer is reset at startup, after waking from sleep, and after a certain amount of time has passed since startup.
Methods
set_led()
void set_led(uint8_t mode, uint16_t tick)
Controls LED (D1).
mode
takes the following parameters. tick
specifies the ON duration [ms], but see the explanation of mode
for details.
Mode | Description |
---|---|
LED_TIMER::BLINK | Blinks the LED. Toggles ON/OFF every tick ms. After waking from sleep, it resets and starts ON. |
LED_TIMER::ON_RX | Turns on the LED for tick ms when a packet is received. |
LED_TIMER::ON_TX_COMP | Turns on the LED for tick ms when transmission completes. |
led_one_shot()
void led_one_shot(uint16_t tick)
Turns on the LED for a specified duration. Cannot be used simultaneously with set_led()
.
get_D1() .. D4(), get_DIPSW_BM()
inline uint8_t get_D1()
inline uint8_t get_D2()
inline uint8_t get_D3()
inline uint8_t get_D4()
inline uint8_t get_DIPSW_BM()
get_D1()
through get_D4()
return 0
when the DIP switch is in the HIGH (up) position, and 1
when in the LOW (down) position.
get_DIPSW_BM()
returns the DIP switch setting as a value from 0
to 15
, calculated as: SW1==LOW
= 1, SW2==LOW
= 2, SW3==LOW
= 4, and SW4==LOW
= 8.
The logic here is inverted from the actual HIGH(1)/LOW(0) levels of D1–D4.
This is because a DIP switch in the LOW(0) position is considered “set” and assigned a value of 1
.
1.1.9.2.1 - <PAL_NOTICE>
This board behavior is for the NOTICE PAL.
In addition to the common definitions, this behavior enables access to onboard sensors.
- LED driver PCA9632
- Accelerometer MC3630
void setup() {
auto&& brd = the_twelite.board.use<PAL_NOTICE>();
}
Member Objects
sns_PCA9632
Object for the PCA9632 device. The board definition handles Wire initialization and device setup. Use the control methods described later to interact with the device.
If using a coin battery, pulsed lighting (e.g., flashing briefly every second) can reduce peak current draw.
For example, turning on the LED for about 20ms every 1 second can still appear bright enough while minimizing the current (e.g., 5mA * 20ms per second = 0.1mA average).
sns_MC3630
Object for the MC3630 sensor. Handles SPI setup, device initialization, and interrupt processing. Use the methods provided in sns_MC3630
.
PCA9632 Definitions
static const uint8_t LED_OFF = SnsPCA9632::LED_OFF;
static const uint8_t LED_ON = SnsPCA9632::LED_PWM;
static const uint8_t LED_BLINK = SnsPCA9632::LED_BLINK;
static const uint8_t LED_NOP = SnsPCA9632::LED_NOP;
static const uint8_t LED_R = SnsPCA9632::LED1;
static const uint8_t LED_G = SnsPCA9632::LED2;
static const uint8_t LED_B = SnsPCA9632::LED3;
static const uint8_t LED_W = SnsPCA9632::LED4;
static const uint8_t LED_REG_MAX_PWM = 127;
static const uint8_t LED_REG_BOOST_PWM = 255;
LED States
Definition | Description |
---|---|
PAL_NOTICE::LED_OFF | Off |
PAL_NOTICE::LED_ON | On (PWM brightness control) |
PAL_NOTICE::LED_BLINK | Blinking |
PAL_NOTICE::LED_NOP | No change |
LED Identifiers
Definition | Description |
---|---|
PAL_NOTICE::LED_R | Red LED |
PAL_NOTICE::LED_G | Green LED |
PAL_NOTICE::LED_B | Blue LED |
PAL_NOTICE::LED_W | White LED |
Register Brightness Settings
Definition | Description |
---|---|
PAL_NOTICE::LED_REG_MAX_PWM | Standard brightness PWM register value (approx. 50%) |
PAL_NOTICE::LED_REG_BOOST_PWM | Boost brightness PWM register value |
PCA9632 Control Methods
Master Switch
void set_led_master_sw_on() { digitalWrite(PIN_SNS_EN, LOW); }
void set_led_master_sw_off() { digitalWrite(PIN_SNS_EN, HIGH); }
NOTICE PAL includes a FET switch after the PCA9632 output. LEDs will not light unless this switch is turned ON.
LED State Control
void set_led_r_blink()
void set_led_r_on()
void set_led_r_off()
void set_led_g_on()
void set_led_g_blink()
void set_led_g_off()
void set_led_b_on()
void set_led_b_blink()
void set_led_b_off()
void set_led_w_on()
void set_led_w_blink()
void set_led_w_off()
These functions set individual LEDs to ON, OFF, or BLINK state.
void set_leds(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
void set_leds_off()
set_leds()
controls the state of all LEDs. Each parameter must be one of: PAL_NOTICE::LED_OFF
, PAL_NOTICE::LED_ON
, PAL_NOTICE::LED_BLINK
, or PAL_NOTICE::LED_NOP
.
LED Brightness Control
void set_led_brightness_r_reg(uint8_t duty)
void set_led_brightness_g_reg(uint8_t duty)
void set_led_brightness_b_reg(uint8_t duty)
void set_led_brightness_w_reg(uint8_t duty)
void set_leds_brightness_reg(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
void set_led_brightness_r1000(uint16_t duty, bool boost = false)
void set_led_brightness_g1000(uint16_t duty, bool boost = false)
void set_led_brightness_b1000(uint16_t duty, bool boost = false)
void set_led_brightness_w1000(uint16_t duty, bool boost = false)
void set_leds_brightness1000(
uint16_t r, uint16_t g, uint16_t b, uint16_t w, bool boost = false)
Controls PWM duty cycle (brightness) of LEDs.
set_led_brightness_?_reg()
and set_leds_brightness_reg()
directly specify 0–255 register values, where brightness is duty/256
.
set_led_brightness_?1000()
and set_leds_brightness1000()
accept values from 0 to 1000. 0 means off, higher values increase brightness. When boost=false
, a value of 1000 maps to register value 127; when boost=true
, it maps to 255.
Blink Control
void set_blink_cycle_ms(uint16_t x)
void set_blink_duty1000(uint16_t x)
LEDs set to PAL_NOTICE::LED_BLINK
blink based on the specified cycle and duty.
- Per-LED blinking patterns are not supported.
- Brightness during blink is set by the current PWM duty configuration.
set_blink_cycle_ms()
sets blink cycle in milliseconds.
set_blink_duty1000()
sets ON duration as cycle * x / 1000
.
LED Test
void test_led()
Briefly lights up all four LEDs. After this, the master switch is left ON (set_led_master_sw_on()
).
1.1.9.2.2 - <PAL_AMB>
In addition to the common definitions, this behavior enables access to onboard sensors.
- Temperature and Humidity Sensor SHTC3
- Ambient Light Sensor LTR308ALS
void setup() {
auto&& brd = the_twelite.board.use<PAL_AMB>();
}
Member Objects
sns_SHTC3
Object for the SHTC3 sensor.
sns_LTR308ALS
Object for the LTR-308ALS sensor.
1.1.9.2.3 - <PAL_MAG>
This board behavior is for the Open-Close Sensor PAL.
void setup() {
auto&& brd = the_twelite.board.use<PAL_MAG>();
}
The sensor on the Open-Close Sensor PAL is a magnetic sensor with two interrupt input lines only.
const uint8_t PAL_MAG::PIN_SNS_NORTH = 16;
const uint8_t PAL_MAG::PIN_SNS_OUT1 = 16;
const uint8_t PAL_MAG::PIN_SNS_SOUTH = 17;
const uint8_t PAL_MAG::PIN_SNS_OUT2 = 17;
PAL_MAG::PIN_SNS_NORTH
triggers an interrupt when the sensor detects the north pole; PAL_MAG::PIN_SNS_SOUTH
also triggers an interrupt upon detecting the north pole.
Configure the following before entering sleep:
pinMode(PAL_MAG::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
pinMode(PAL_MAG::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
On wake-up, check the GPIO that triggered the wake-up:
uint8_t b_north =
the_twelite.is_wokeup_by_dio(PAL_MAG::PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(PAL_MAG::PIN_SNS_SOUTH);
1.1.9.2.4 - <PAL_MOT>
This board behavior is for the Motion Sensor PAL.
In addition to the common definitions, this behavior enables access to onboard sensors.
- Accelerometer MC3630
void setup() {
auto&& brd = the_twelite.board.use<PAL_MOT>();
}
Member Objects
sns_MC3630
Object for the MC3630 sensor.
1.1.9.3 - <ARIA>
Enables access to the onboard accelerometer, magnetic sensor, and LED.
- Temperature/Humidity Sensor
- Magnetic Sensor
- LED
void setup() {
auto&& brd = the_twelite.board.use<ARIA>();
}
Temperature/Humidity Sensor
A member object for the SHT4x sensor (sns_SHT4x
) is defined.
Magnetic Sensor
The sensor used in the Door Sensor PAL is a magnetic sensor that only has two interrupt input lines.
const uint8_t CUE::PIN_SNS_NORTH = 16;
const uint8_t CUE::PIN_SNS_OUT1 = 16;
const uint8_t CUE::PIN_SNS_SOUTH = 8;
const uint8_t CUE::PIN_SNS_OUT2 = 8;
ARIA::PIN_SNS_NORTH
triggers an interrupt when the sensor detects the north pole.
ARIA::PIN_SNS_SOUTH
also triggers an interrupt when the sensor detects the north pole.
Before entering sleep, configure the pins as follows:
pinMode(CUE::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
pinMode(CUE::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
On wake-up, check the cause using:
uint8_t b_north =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_SOUTH);
LED
set_led()
void set_led(uint8_t mode, uint16_t tick)
Controls the LED (D1).
mode
accepts the following parameters. tick
specifies the lighting duration in milliseconds [ms]. Refer to the mode descriptions for details.
Value | Description |
---|---|
LED_TIMER::BLINK | Blinks the LED. Toggles ON/OFF at intervals specified by tick [ms]. After waking from sleep, the timer resets and starts in the ON state. |
LED_TIMER::ON_RX | Turns on the LED for the specified tick duration [ms] when a packet is received. |
LED_TIMER::ON_TX_COMP | Turns on the LED for the specified tick duration [ms] when transmission completes. |
led_one_shot()
void led_one_shot(uint16_t tick)
Turns on the LED for a specified duration. Cannot be used simultaneously with set_led()
.
Watchdog Timer
Resets the external watchdog timer at startup, upon waking from sleep, and after a certain time has elapsed post-startup.
1.1.9.4 - <CUE>
Provides access to the onboard accelerometer, magnetic sensor, and LED.
- Accelerometer
- Magnetic Sensor
- LED
void setup() {
auto&& brd = the_twelite.board.use<CUE>();
}
Accelerometer
The member object (sns_MC3630
) of the MC3630 sensor is defined.
Magnetic Sensor
The sensor used in the Door Sensor PAL is a magnetic sensor, with two interrupt input lines only.
const uint8_t CUE::PIN_SNS_NORTH = 16;
const uint8_t CUE::PIN_SNS_OUT1 = 16;
const uint8_t CUE::PIN_SNS_SOUTH = 8;
const uint8_t CUE::PIN_SNS_OUT2 = 8;
CUE::PIN_SNS_NORTH
triggers an interrupt when the north pole is detected; CUE::PIN_SNS_SOUTH
also triggers on north pole detection.
Configure the following before entering sleep:
pinMode(CUE::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
pinMode(CUE::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
On wake-up, check which GPIO triggered the event:
uint8_t b_north =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_NORTH);
uint8_t b_south =
the_twelite.is_wokeup_by_dio(CUE::PIN_SNS_SOUTH);
LED
set_led()
void set_led(uint8_t mode, uint16_t tick)
Controls LED (D1).
mode
takes the following parameters. tick
specifies the lighting duration [ms]; see the explanation of mode
for details.
Value | Description |
---|---|
LED_TIMER::BLINK | Blinks the LED. Toggles ON/OFF every tick milliseconds. Resets counter after sleep and starts ON. |
LED_TIMER::ON_RX | Turns on LED for tick milliseconds upon packet reception. |
LED_TIMER::ON_TX_COMP | Turns on LED for tick milliseconds when transmission completes. |
led_one_shot()
void led_one_shot(uint16_t tick)
Turns on LED for a specified duration. Cannot be used simultaneously with set_led()
.
Watchdog Timer
Resets the external watchdog timer at startup, after waking from sleep, and after a certain time post-start.
1.1.9.5 - <MONOSTICK>
Constants
The following constants are defined:
const uint8_t PIN_LED = mwx::PIN_DIGITAL::DIO16; // LED
const uint8_t PIN_WDT = mwx::PIN_DIGITAL::DIO9; // WDT (shall tick < 1sec)
const uint8_t PIN_WDT_EN = mwx::PIN_DIGITAL::DIO11; // WDT (LO as WDT enabled)
const uint8_t PIN_LED_YELLOW = mwx::PIN_DIGITAL::DO1; // YELLOW LED
Accessible via MONOSTICK::PIN_LED
.
Hardware Initialization
pinMode(PIN_LED, OUTPUT_INIT_HIGH);
pinMode(PIN_WDT, OUTPUT_INIT_LOW);
pinMode(PIN_WDT_EN, OUTPUT_INIT_LOW);
pinMode(PIN_LED_YELLOW, OUTPUT);
Pins are initialized as shown in the code above.
Watchdog Timer
The external watchdog timer is reset at startup, after waking from sleep, and after a set duration.
The watchdog timeout is one second.
Although MONOSTICK typically runs non-sleeping applications, if using sleep, set MONOSTICK::PIN_WDT_EN
to HIGH before sleeping.
Methods
set_led()
void set_led_red(uint8_t mode, uint16_t tick)
void set_led_yellow(uint8_t mode, uint16_t tick)
Controls the red and yellow LEDs.
The yellow LED (MONOSTICK::PIN_LED_YELLOW
) is the SPIMISO pin (semiconductor pin name DO1). This board behavior does not include methods or procedures for PWM control. Implement the following steps if needed:
- Avoid calling
set_led_yellow()
. - Initialize PWM output separately after startup. The SPIMISO pin corresponds to PWM3 in App_Twelite and can be controlled by the Timer3 class object.
- Reinitialize PWM output after waking from sleep. At that time, disable output settings for DO1.
- Disable DO1 output before configuring PWM:
pinMode(PIN_LED_YELLOW, DISABLE_OUTPUT);
MONOSTICK::PIN_LED_YELLOW
) cannot be lit during sleep.mode
accepts the following parameters. tick
specifies the lighting duration in milliseconds [ms]; see the descriptions for each mode below.
Parameter | Meaning |
---|---|
LED_TIMER::BLINK | The LED blinks. ON/OFF toggles every tick milliseconds. After waking from sleep, the count resets and starts in the ON state. |
LED_TIMER::ON_RX | Lights the LED for tick milliseconds upon packet reception. |
LED_TIMER::ON_TX_COMP | Lights the LED for tick milliseconds upon transmission completion. |
1.1.10 - Sensor Devices (SNS)
Procedures for Handling Sensors
For sensors like temperature sensors, procedures such as sensor activation → waiting time → value reading are often common.
Make sure to call Wire.begin()
before using I2C sensors. After waking from sleep, reinitialization of Wire is done automatically, so no special code is required (Note: if Wire.end()
is explicitly called in user code, reinitialization must be described in wakeup()
).
void setup() {
auto&& brd = the_twelite.board.use<PAL_AMB>();
..
Wire.begin();
brd.sns_SHTC3.begin();
brd.sns_LTR308ALS.begin();
}
Procedures after starting the reading differ by sensor type. For example, both sensors in <PAL_AMB>
manage elapsed time. To notify the sensor object of the elapsed time, use the process_ev()
method.
void loop() {
auto&& brd = the_twelite.board.use<PAL_AMB>();
// mostly process every ms.
if (TickTimer.available()) {
// wait until sensor capture finish
if (!brd.sns_LTR308ALS.available()) {
brd.sns_LTR308ALS.process_ev(E_EVENT_TICK_TIMER);
}
if (!brd.sns_SHTC3.available()) {
brd.sns_SHTC3.process_ev(E_EVENT_TICK_TIMER);
}
..
In the above example, TickTimer
triggers every 1 ms to notify the elapsed time. E_EVENT_TICK_TIMER
conveys the 1 ms passage to the sensor object.
When sufficient time has passed due to wake-up from sleep, use E_EVENT_START_UP
instead. The sensor object will then quickly become ready for reading.
Common Sensor Methods
setup()
void setup(uint32_t arg1 = 0, uint32_t arg2 = 0)
Initializes the sensor.
begin()
, end()
void begin(uint32_t arg1 = 0, uint32_t arg2 = 0)
void end()
Starts or stops sensor acquisition.
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
For sensors that require a wait period, pass E_EVENT_TICK_TIMER
or E_EVENT_START_UP
to arg1
to notify time progress. If sufficient time has passed after this call, available
will become true, and sensor values can be read.
available()
bool available()
Returns true
when the sensor is ready for reading.
probe()
bool probe()
(Only for supported sensors) Returns true
when the sensor is connected.
probe()
may fail.1.1.10.1 - SHTC3
<PAL_AMB>
is loaded. Procedures for common methods other than begin()
are executed within the board behavior.Processing Flow
Wire.begin()
: Initialize the bus.begin()
: Start sensor operation- Wait a few milliseconds
.available()
becomestrue
.get_temp(), .get_humid()
: Read the values
Required Procedures for Operation
Wire Bus
Ensure the Wire is active using Wire.begin()
before calling the begin()
method.
Procedure After Wake-up from Sleep
Ensure the Wire bus is active just before entering sleep (it will be automatically recovered after waking up).
Methods
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
Reads the temperature. get_temp()
returns the value in °C, and get_temp_cent()
returns the temperature multiplied by 100 as an integer.
On error, a value between -32760 and -32768 is returned.
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
Reads the humidity. get_humid()
returns the value in %, and get_humid_per_dmil()
returns the humidity multiplied by 100 as an integer.
On error, a value between -32760 and -32768 is returned.
Common Methods
setup()
void setup()
Allocates memory and performs initialization for the sensor.
begin()
, end()
void begin()
void end()
Starts sensor data acquisition. It requires approximately 5ms of wait time before values can be read.
end()
is not supported.
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
For sensors requiring wait-time processing, pass E_EVENT_TICK_TIMER
or E_EVENT_START_UP
to arg1
to notify time progression. After calling this method and enough time has passed, the sensor becomes available and its value can be read.
available()
bool available()
Returns true
when the sensor meets the read condition.
probe()
bool probe()
Returns true
when the sensor is connected.
1.1.10.2 - SHT3x
This sensor is not used in the TWELITE PAL series. For usage examples, refer to:
Processing Flow
Wire.begin()
: Initialize the bus.setup()
: Initialize the sensor.begin()
: Start the sensor- Wait for a few milliseconds
.available()
becomestrue
.get_temp(), .get_humid()
: Read values
Required Procedures for Operation
Wire Bus
Before calling the setup()
method, initialize the Wire with Wire.begin()
.
Procedure After Waking from Sleep
Ensure the Wire bus is active just before entering sleep (Wire will be automatically recovered after waking).
Code Example
##include <TWELITE>
##include <SNS_SHT3X>
SNS_SHT3X sns_sht3x; // Declare the object
Include #include <SNS_SHT3X>
and declare an object of the SNS_SHT3X
class.
Initialization
void setup() {
Wire.begin();
sns_sht3x.setup();
}
Starting Sensor Reading
void loop() {
if(eState == E_STATE::INIT) {
sns_sht3x.begin();
eState = E_STATE::CAPTURE;
}
}
To begin reading sensor values, call .begin()
. It takes a few milliseconds to complete.
※ The above loop()
assumes a state-machine design using the eState
variable. (Reference)
Waiting for Sensor Reading
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_sht3x.available()) {
// Sensor values are ready
}
}
}
Check .available()
to determine whether the sensor values are ready.
Reading Sensor Values
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_sht3x.available()) {
Serial << crlf << "SHT3X:"
<< " T=" << sns_sht3x.get_temp() << 'C'
<< " H=" << sns_sht3x.get_humid() << '%';
}
}
}
Once the sensor values are ready, you can read them.
.get_temp()
and .get_humid()
use floating point operations. You can also retrieve values as integers scaled by 100.
auto temp = div100(sns_sht3x.get_temp_cent());
auto humd = div100(sns_sht3x.get_humid_per_dmil);
Serial << crlf << "SHT3X:"
<< format(" T=%c%d.%02d", temp.neg ? '-' : ' ', temp.quo, temp.rem)
<< format(" H=%c%d.%02d", humd.neg ? '-' : ' ', humd.quo, humd.rem);
In this example, div100()
is used to split the x100 values into integer and fractional parts.
Methods
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
Reads the temperature. get_temp()
returns °C, while get_temp_cent()
returns the value scaled by 100 as an integer.
On error, it returns a value between -32760 and -32768.
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
Reads the humidity. get_humid()
returns %RH, while get_humid_per_dmil()
returns the value scaled by 100 as an integer.
On error, it returns a value between -32760 and -32768.
Common Methods
setup()
void setup(uint32_t arg1 = 0UL)
Allocates memory and initializes the sensor.
You can specify the I2C address in the lower 8 bits of arg1
. If unspecified, it defaults to 0.
##include <SNS_SHT3X>
SNS_SHT3X sns_sht3x;
bool b_found_sht3x = false;
void setup() {
sns_sht3x.setup();
if (!sns_sht3x.probe()) {
delayMicroseconds(100); // just in case, wait for devices to listen further I2C comm.
sns_sht3x.setup(0x45); // alternative ID
if (sns_sht3x.probe()) b_found_sht3x = true;
} else {
b_found_sht3x = true;
}
}
In this example, it first tries to initialize with the default I2C ID. If no response, it retries with address 0x45
.
begin()
, end()
void begin()
void end()
Begins sensor reading. It takes a few milliseconds before values become ready, during which .available()
returns false.
end()
is not supported.
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
For sensors that require waiting, provide E_EVENT_TICK_TIMER
or E_EVENT_START_UP
in arg1
to notify the passage of time. If enough time has elapsed after calling this method, .available()
will return true and the sensor value can be read.
available()
bool available()
Returns true
when the sensor is ready to be read.
probe()
bool probe()
Returns true
if the sensor is connected.
sns_stat()
uint32_t sns_stat()
Stores various information about the sensor device.
- The stored value is undefined for this device.
sns_opt()
uint32_t& sns_opt()
Returns the value passed to setup(uint32_t arg1)
.
- The lower 8 bits store the specified I2C device address.
1.1.10.3 - LTR-308ALS
<PAL_AMB>
is loaded. Common method procedures other than begin()
are executed within the board behavior.Processing Flow
Wire.begin()
: Initialize the bus.begin()
: Start sensor operation- Wait for 50ms
.available()
becomestrue
.get_luminance()
: Read the value
Required Procedures for Operation
Wire Bus
Before calling the .begin()
method, ensure the Wire is initialized using Wire.begin()
.
Procedures When Waking from Sleep
Ensure the Wire bus is active just before entering sleep (it will automatically recover Wire after waking from sleep).
Method
get_luminance()
uint32_t get_luminance()
Returns the illuminance [lx] as an integer value.
Returns -1
in case of an error.
Common Methods
setup()
void setup()
Allocates memory area for the sensor and performs initialization.
begin()
, end()
void begin()
void end()
Starts sensor acquisition. A wait time of about 50ms is required before reading the sensor value.
end()
is not supported.
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
For sensors that require wait time processing, provide E_EVENT_TICK_TIMER
or E_EVENT_START_UP
in arg1
to notify elapsed time. After this method is called and the required time has elapsed, it will become available and the sensor value can be read.
available()
bool available()
Returns true
when the sensor satisfies the read condition.
probe()
bool probe()
Returns true
when the sensor is connected.
1.1.10.4 - MC3630
<PAL_MOT>
or <PAL_NOTICE> <CUE>
is loaded. Procedures for common methods other than begin()
and available()
are executed within the board behavior.Operation Flow
.begin()
: Start sensor operationPIN_SNS_INT
interrupt oravailable()
: FIFO queue reaches the specified number of samples.get_que()
: Retrieve data from the FIFO queue
Required Procedures for Operation
SPI Bus
No special setup is required.
Sleep Procedure
To allow wake-up via PIN_SNS_INT
interrupt, configure the following before entering sleep:
pinMode(PAL_MOT::PIN_SNS_INT, WAKE_FALLING);
Procedure Upon Wake-up
Call the .wakeup()
method. This process is handled within the <PAL_MOT>
board behavior.
Data Structure
Each sample is stored in a queue smplque
of axis_xyzt
structures. The x
, y
, and z
members represent the X, Y, and Z axes, respectively.
struct axis_xyzt {
int16_t x;
int16_t y;
int16_t z;
uint16_t t;
};
Each axis value is stored with 1G equivalent to 1000. The t
value represents the sample index, starting from 0 and incrementing with each sample.
Methods
read()
uint8_t read()
Reads data from the semiconductor’s FIFO queue. The return value is the number of bytes read. Use .get_que()
to access the queue and retrieve the number of samples stored.
read()
is executed after waking from sleep in <PAL_MOT>
.get_que()
smplque<axis_xyzt>& get_que()
Retrieves acceleration samples. The queue is a smplque
of axis_xyzt
. Once available
is true, promptly clear the queue.
Common Methods
setup()
void setup()
setup()
is not used for this sensor.
begin()
, end()
void begin(uint32_t conf)
void end()
Initializes the sensor with the specified conf
.
conf[0:15]
(bit 0–15): Sampling mode, conf[16:23]
(bit 16–23): Acceleration range, conf[24:31]
(bit 24–31): Number of samples before triggering interrupt.
conf[0:15] Sample Mode | Description |
---|---|
MODE_LP_1HZ_UNOFFICIAL | 1Hz Low Power (unofficial) |
MODE_LP_2HZ_UNOFFICIAL | 2Hz Low Power (unofficial) |
MODE_LP_7HZ_UNOFFICIAL | 7Hz Low Power (unofficial) |
MODE_LP_14HZ | 14Hz Low Power (default) |
MODE_LP_28HZ | 28Hz Low Power |
MODE_LP_54HZ | 54Hz Low Power |
MODE_LP_105HZ | 105Hz Low Power |
MODE_LP_210HZ | 210Hz Low Power |
MODE_LP_400HZ | 400Hz Low Power |
MODE_ULP_25HZ | 25Hz Ultra Low Power |
MODE_ULP_50HZ | 50Hz Ultra Low Power |
MODE_ULP_100HZ | 100Hz Ultra Low Power |
MODE_ULP_190HZ | 190Hz Ultra Low Power |
MODE_ULP_380HZ | 380Hz Ultra Low Power |
conf[16:23] Acceleration Range | Description |
---|---|
RANGE_PLUS_MINUS_8G | ±8G (default) |
RANGE_PLUS_MINUS_4G | ±4G |
RANGE_PLUS_MINUS_2G | ±2G |
RANGE_PLUS_MINUS_1G | ±1G |
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
process_ev()
is not used for this sensor.
available()
bool available()
Returns true
when data has been read into the internal queue.
probe()
bool probe()
probe()
is not used for this sensor.
wakeup()
void wakeup()
Reinitializes the SPI bus after waking from sleep and reads acceleration data.
1.1.10.5 - BMx280
This sensor is not used in the TWELITE PAL series. Please refer to the following for usage examples.
Process Flow
Wire.begin()
: Initialize the bus.setup()
: Initialize the sensor.begin()
: Start sensor operation- Wait for several milliseconds
.available()
becomestrue
.get_press(), .get_temp(), .get_humid()
: Read values
Procedures Required for Operation
Wire Bus
Before calling the setup()
method, ensure Wire is operational by calling Wire.begin()
.
Procedures for Sleep Wake-up
Before entering sleep, keep the Wire bus operational (Wire will automatically recover after waking from sleep).
Code Example
##include <TWELITE>
##include <SNS_BME280>
SNS_BME280 sns_bme280; // Declare the object
You need to include #include <SNS_SHT3X>
and declare an SNS_SHT3X
class object.
Initialization
void setup() {
Wire.begin();
sns_bme280.setup();
}
Start Getting Sensor Values
void loop() {
if(eState == E_STATE::INIT) {
sns_bme280.begin();
eState = E_STATE::CAPTURE;
}
}
Call .begin()
to start getting sensor values. It takes several milliseconds to complete.
Note: The above loop()
is designed to branch processing based on the state variable eState
. (Reference)
Waiting for Sensor Value Acquisition
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_bme280.available()) {
// Sensor values ready to read
}
}
}
You can check if sensor values are ready by .available()
.
Reading Sensor Values
void loop() {
if(eState == E_STATE::CAPTURE) {
if (sns_bme280.available()) {
Serial << crlf << "BMx280:"
<< " P=" << int(sns_bme280.get_press()) << "hPa";
<< " T=" << sns_bme280.get_temp() << 'C'
<< " H=" << sns_bme280.get_humid() << '%';
}
}
}
Once sensor values are ready, you can read them.
.get_temp(), get_humid()
involve floating-point operations. You can also get values as integers multiplied by 100.
auto temp = div100(sns_bme280.get_temp_cent());
auto humd = div100(sns_bme280.get_humid_per_dmil);
Serial << crlf << "BMx280:"
<< " P=" << int(sns_bme280.get_press()) << "hPa";
<< format(" T=%c%d.%02d", temp.neg ? '-' : ' ', temp.quo, temp.rem)
<< format(" H=%c%d.%02d", humd.neg ? '-' : ' ', humd.quo, humd.rem);
Here, div100()
is used to split the value multiplied by 100 into integer and fractional parts.
Methods
get_press()
int16_t get_press()
Reads pressure. The unit is hectopascal (hPa), usually around 1000.
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
Reads temperature. get_temp()
returns °C as a double, and get_temp_cent()
returns temperature multiplied by 100 as an integer.
Returns values between -32760
and -32768
on error.
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
Reads humidity. get_humid()
returns % as a double, and get_humid_per_dmil()
returns humidity multiplied by 100 as an integer.
Returns values between -32760
and -32768
on error.
Common Methods
setup()
void setup(uint32_t arg1 = 0UL)
Allocates memory and initializes the sensor.
The lower 8 bits of arg1
can store the I2C address. If not specified, it defaults to 0.
##include <SNS_BME280>
SNS_BME280 sns_bme280;
bool b_found_bme280 = false;
void setup() {
...
sns_bme280.setup();
if (!sns_bme280.probe()) {
delayMicroseconds(100); // device needs small time for further I2C comm.
sns_bme280.setup(0x77); // alternative ID
if (sns_bme280.probe()) b_found_bme280 = true;
} else {
b_found_bme280 = true;
}
...
The code first tries the default I2C ID to check device response; if no response, tries 0x77
as an alternative.
begin()
, end()
void begin()
void end()
Starts sensor acquisition. It takes several milliseconds to read sensor values; wait until available()
returns true
.
end()
is not supported.
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
For sensors with wait time processing, pass E_EVENT_TICK_TIMER
or E_EVENT_START_UP
in arg1
to notify elapsed time. After this call, if enough time has passed, available()
will return true
and sensor values can be read.
available()
bool available()
Returns true
when sensor reading conditions are met.
probe()
bool probe()
Returns true
when the sensor is connected.
sns_stat()
uint32_t sns_stat()
Contains various sensor device information.
- The lower 8 bits store the chip model of BME280/BMP280.
0x60
means BME280, and0x58
means BMP280.
sns_opt()
uint32_t& sns_opt()
Stores the value passed to setup(uint32_t arg1)
.
- The lower 8 bits store the specified I2C device address.
1.1.10.6 - PCA9632
Processing Flow
Wire.begin()
: Initialize the bus.setup()
: Initialize the class object.reset()
: Initialize the driver- Execute various operations
About PCA9632
It is a 4-channel LED driver.
- Each channel can be set to OFF, ON, PWM, or BLINK mode
- Each channel supports independent brightness control via PWM
- All channels set to blink will share the same blink pattern
- Individual brightness control (via PWM) is available even in blink mode
Required Procedures for Operation
Wire Bus
Ensure the Wire is initialized via Wire.begin()
before calling the setup()
method.
Procedure Upon Wake from Sleep
Ensure the Wire bus is active right before entering sleep (Wire will be automatically recovered after waking up).
Code Example
##include <TWELITE>
##include <SNS_PCA9632>
SNS_PCA9632 pca;
Include #include <SNS_PCA9632>
and declare an instance of the SNS_PCA9632
class.
Initialization & Reset
void setup() {
Wire.begin();
pca.setup();
pca.reset();
}
Lighting Up
...
pca.set_led_duty_all(
127,
127,
127,
127
);
pca.set_led_status(
SNS_PCA9632::LED_PWM,
SNS_PCA9632::LED_NOP,
SNS_PCA9632::LED_PWM,
SNS_PCA9632::LED_NOP);
In the example above, LED1 and LED3 are lit using PWM control.
Methods
Constructor, setup()
SnsPCA9632(uint8_t i2c_addr = DEFAULT_I2C_ADDRESS)
void setup(uint8_t i2c_addr = DEFAULT_I2C_ADDRESS)
The constructor allows specifying the i2c_addr
.
If the class object is defined globally, the constructor is not called automatically, so ensure to call setup()
.
reset()
bool reset()
Initializes the device.
Writes the following values to registers starting at address 0x0:
{0x81, 0x35, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x0B, 0x00}
set_mode2()
bool set_mode2(uint8_t u8var = 0x35)
Writes the specified value to the MODE2 register.
set_power_mode()
bool set_power_mode(bool b_pow_on)
Set b_pow_on
to true
for normal operation, or false
to enter sleep mode.
set_blink_cycle()
, set_blink_cycle_ms()
bool set_blink_cycle(uint8_t u8var)
bool set_blink_cycle_ms(uint16_t u16ms)
Sets the blink (group PWM) cycle.
If u8var
is specified, the cycle is (u8var+1)/24
seconds.
If u16ms
is specified, it sets the cycle in milliseconds.
set_blink_duty()
bool set_blink_duty(uint8_t u8duty);
Sets the duty ratio of the blink (group PWM). The lit duration becomes u8duty/256
, where 0 is OFF and 255 is fully ON.
set_led_duty()
bool set_led_duty(uint8_t port, uint8_t duty)
Sets the brightness (PWM duty ratio).
port
specifies the target LED (SNS_PCA9632::LED1..4
).
duty
specifies a value from 0 to 255, with a brightness ratio of duty/256
.
set_led_duty_all()
bool set_led_duty_all(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4)
Sets the brightness (PWM duty ratio) for all LEDs.
p1, p2, p3, p4
correspond to LED1..4. Each takes a value from 0 to 255, with a brightness ratio of duty/256
.
set_led_status()
bool set_led_status(uint8_t u8led1, uint8_t u8led2, uint8_t u8led3, uint8_t u8led4)
Sets the ON/OFF status for all LEDs.
u8led1..4
specify the state of LED1 to LED4.
Available states:
Description | |
---|---|
SNS_PCA9632::LED_OFF | OFF |
SNS_PCA9632::LED_ON | ON |
SNS_PCA9632::LED_PWM | PWM brightness control |
SNS_PCA9632::LED_BLINK | Blink control (group PWM) |
SNS_PCA9632::LED_NOP | Do not change the current state |
probe()
bool probe()
Returns true
if the device is present on the I2C bus.
show_registers()
void show_registers()
Displays values of registers (0x0–0x8).
1.1.10.7 - SHT4x
<ARIA>
is loaded. Procedures for common methods other than begin()
are executed within the board behavior.Processing Flow
Wire.begin()
: Initialize the bus.begin()
: Start sensor operation- Wait a few milliseconds
.available()
becomestrue
.get_temp(), .get_humid()
: Read the values
Required Procedures for Operation
Wire Bus
Ensure the Wire is active using Wire.begin()
before calling the begin()
method.
Procedure After Wake-up from Sleep
Ensure the Wire bus is active just before entering sleep (it will be automatically recovered after waking up).
Methods
get_temp()
, get_temp_cent()
double get_temp()
int16_t get_temp_cent()
Reads the temperature. get_temp()
returns the value in °C, and get_temp_cent()
returns the temperature multiplied by 100 as an integer.
On error, a value between -32760 and -32768 is returned.
get_humid()
, get_humid_per_dmil()
double get_humid()
int16_t get_humid_per_dmil()
Reads the humidity. get_humid()
returns the value in %, and get_humid_per_dmil()
returns the humidity multiplied by 100 as an integer.
On error, a value between -32760 and -32768 is returned.
Common Methods
setup()
void setup()
Allocates memory and performs initialization for the sensor.
begin()
, end()
void begin()
void end()
Starts sensor data acquisition. It requires approximately 5ms of wait time before values can be read.
end()
is not supported.
process_ev()
void process_ev(uint32_t arg1, uint32_t arg2 = 0)
For sensors requiring wait-time processing, pass E_EVENT_TICK_TIMER
or E_EVENT_START_UP
to arg1
to notify time progression. After calling this method and enough time has passed, the sensor becomes available and its value can be read.
available()
bool available()
Returns true
when the sensor meets the read condition.
probe()
bool probe()
Returns true
when the sensor is connected.
1.1.11 - Network Behavior (NWK)
<NWK_SIMPLE>
- A very simple relay network.<NWK_LAYERED>
- A simplified tree structure network with layers. (Note: MWX only supports parent nodes that receive data.)
1.1.11.1 - Simple Relay Network <NWK_SIMPLE>
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0xFE)
<< NWK_SIMPLE::repeat_max(3);
The above is an example of network usage declaration and configuration. The basic concept of network addresses and other fundamental content will be explained first, with details provided later.
Each wireless station in this network is identified by an 8-bit logical ID. This value is independently set by each wireless station at startup. Logical IDs can be duplicated, but communication must be conducted assuming duplication.
Set the ID of each wireless station. Usually, the network consists of a wireless station acting as a parent and wireless stations acting as children. It is also possible to operate a network with only child stations.
Child stations also serve as relay stations.
Wireless Station ID | Role |
---|---|
0x00 | Parent Station |
0x01 ..0xEF | Child Station |
0xFE | Child Station without assigned ID |
Logical IDs can be specified as destinations, but 0xFE
and 0xFF
have special meanings. The following table summarizes destination specifications.
Destination ID | Meaning |
---|---|
0x00 | Specifies the parent from a child. Invalid when specified from the parent. |
0x01 ..0xEF | Specifies a specific child station. |
0xFE | Broadcast to all child stations. |
0xFF | Broadcast to all wireless stations. |
Also, a 32-bit serial number can be used to identify wireless stations.
Packet delivery uses IEEE802.15.4 broadcast. Since ACK is not used, the sender cannot determine delivery success, but an appropriate number of retries is set to achieve the required success rate. If confirmation of arrival is necessary, normal packet communication is used.
For large-scale or frequent communication, this may seem inefficient, but it can be more efficient in networks primarily performing data collection with relatively few relay hops.
Also, since communication for network construction is not required, communication stopping entirely due to failures or exceptional situations is theoretically less likely. If the parent station is in receive mode and within wireless range of the child station, and the child station transmits packets, the parent can receive them in most cases. Networks requiring communication for construction must complete communication to re-establish connection after configuration information is lost. The network behavior <NWK_SIMPLE>
is named “simple” for this reason.
To operate this simple network, it is often necessary to ignore multiple received retransmitted packets (identical packets). Identification of identical packets in <NWK_SIMPLE>
is done using the sender’s serial number and the packet sequence number (called the duplicate checker). The sequence number ranges from 0 to 63 and is assigned sequentially, assuming packets received close in time have close sequence numbers. Sequence numbers considered distant after a certain timeout are excluded from duplication checks.
Considerations for the duplicate checker are as follows.
- Number of elements that can be checked (increasing this increases memory usage and processing time)
- Timeout settings
By default, the timeout is 1 second, and the number of wireless stations checked is 16. That means packets relayed around and older than 1 second are no longer considered duplicates. If packets arrive from more than 16 stations in a short time, duplicate checks cannot be performed for the excess stations.
If there are many relay stations or retransmissions occur at very long intervals, settings may need to be considered.
Declaration and Registration
An example of using the network behavior <NWK_SIMPLE>
.
##include <TWELITE>
##include <NWK_SIMPLE>
void setup() {
...
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
}
Line 2 includes the definition of <NWK_SIMPLE>
. Line 7 registers <NWK_SIMPLE>
with the_twelite
.
Configuration
Configure after registering <NWK_SIMPLE>
.
void setup() {
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0xFE);
}
Configuration is done using the <<
operator.
<<
Operator (Configuration)
The <<
operator is used to perform initial settings on the object the_twelite
.
The following configuration class objects are used as inputs. If not configured, default values apply.
NWK_SIMPLE::logical_id(uint8_t id)
Sets the logical device ID specified by parameter id
. Default is 0xFE
(child without assigned ID).
NWK_SIMPLE::retry_default(uint8_t val)
Sets the default number of retransmissions on send to the value specified by val
.
NWK_SIMPLE::repeat_max(uint8_t val)
Sets the maximum relay count to the value specified by val
. Default is 2
.
Specify 0
to disable relaying.
NWK_SIMPLE::dup_check(uint8_t maxnodes, uint16_t timeout_ms, uint8_t tickscale)
Parameters for the duplicate packet detection algorithm.
maxnodes
is the number of wireless stations (nodes) whose history is kept. If set too low, duplicate exclusion will fail for nodes exceeding this number in a short time, causing multiple data receptions or excessive retransmissions. Default is16
. Each node consumes 21 bytes of memory.timeout_ms
is the timeout in milliseconds before history is erased. Timeout is managed in sequence number blocks and processed per block. Default is1000
ms.tickscale
is the time unit for timeout management,2^tickscale
ms. Time is managed with 7 bits, so set so that127*(2^tickscale) > timeout_ms
. Default is5
(32 ms).
NWK_SIMPLE::secure_pkt(const uint8_t *pukey, bool b_recv_plain_pkt = false)
Enables encrypted packets.
pukey
specifies the encryption key as 16 bytes (128 bit).b_recv_plain_pkt
set totrue
allows receiving plaintext packets with the same application ID and channel.
packet_rx::is_secure_pkt()
, which returns true
(encrypted) or false
(plaintext).STG_STD
Reflects interactive mode settings. The following values are applied.
auto&& set = the_twelite.settings.use<STG_STD>();
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
...
set.reload(); // Load settings
nwk << set; // Apply interactive mode settings
- logical_id
- retry_default
Methods
prepare_tx_packet()
// The type name is packet_tx_nwk_simple<NWK_SIMPLE>, but auto&& is used here.
auto&& preare_tx_packet()
// Example
if (auto&& pkt =
the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
...
pkt.transmit();
}
Obtains a transmission object. The object is derived from packet_tx
. This object stores the transmission address and payload and sends packets with the .transmit()
method.
This object has a bool
operator. If TWENET cannot accept the transmission request at object creation, it returns false
.
Transmission Object
Methods of the transmission object obtained by .prepare_tx_packet()
.
bool
Operator
operator bool()
// Example
if (auto&& pkt =
the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
Returns false
if TWENET cannot accept the transmission request at object creation.
transmit()
MWX_APIRET transmit()
// Example
uint8_t txid;
if (auto&& pkt =
the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
...
MWX_APIRET ret = pkt.transmit();
if (ret) {
txid = pkt.get_value();
}
}
Performs packet transmission. MWX_APIRET
is true
if the transmission request succeeds, but the transmission process does not start at this point.
The packet transmission ID is stored in the value part obtained by .get_value()
of MWX_APIRET
. Transmission completion can be confirmed by the_twelite.tx_status.is_complete()
or transmit_complete()
.
Maximum Packet Length and Structure
The maximum packet length is shown below. When the destination is LID (logical device ID), up to 91 bytes can be included without encryption.
Network Layer | Encryption | Maximum Payload |
---|---|---|
<NWK_SIMPLE> | None | 91 |
<NWK_SIMPLE> | Enabled | 89 |
- Two bytes are reserved for future use. Users may use these reserved bytes if desired.
The packet structure is as follows.
|MacH:XX[........................................]MacF:2|
TWENET:3[.....................]TwenetF:1
NWK_SIMPLE:11|PAYLOAD
(:n is bytes)
1: MacH is the IEEE802.15.4 MAC header information
2: TwenetH is information for TWENET identification
3: NWK_SIMPLE is NWK_SIMPLE network control information
|Type:1|Src LID:1|Src Addr:4|Dest LID:1|Dst Addr:4|Repeat:1|
4: PAYLOAD is the payload
5: TwenetF is the CRC8 checksum (for TWENET packet discrimination)
6: MacF is the CRC16 MAC layer checksum
1.1.11.2 - <NWK_LAYERED>
Initialize in setup()
as follows. Assign the role as a parent using NWK_LAYERED::ROLE_PARENT
.
##include <NWK_LAYERED>
void setup() {
...
auto&& nwk_ly = the_twelite.network.use<NWK_LAYERED>();
nwk_ly << NWK_LAYERED::network_role(NWK_LAYERED::ROLE_PARENT);
// set a role as parent.
}
When a packet is received, on_rx_packet()
is called similarly to NWK_SIMPLE
.
void on_rx_packet(packet_rx& rx, bool_t &handled) {
auto type = rx.get_network_type();
if (type == mwx::NETWORK::LAYERED) {
; // Packet of layered tree network
handled = true; // Mark as handled
}
}
rx
is a class that wraps packet information. Internally, except for setting an internal flag for the processing of _get_network_type()
, no modification of packet information is performed.
In other words, by referring to rx.get_psRxDataApp()
, which returns tsRxDataApp*
, you can obtain the same packet information as in the TWENET C library. packet_rx
defines some procedures to access this information, but the information obtained does not change.
Using with NWK_SIMPLE
When used together with NWK_SIMPLE
, assign NWK_LAYERED
to the_twelite.network
and NWK_SIMPLE
to the_twelite.network2
.
##include <NWK_LAYERED>
##include <NWK_SIMPLE>
void setup() {
...
auto&& nwk_ly = the_twelite.network.use<NWK_LAYERED>();
auto&& nwk_sm = the_twelite.network2.use<NWK_SIMPLE>();
}
void on_rx_packet(packet_rx& rx, bool_t &handled) {
auto type = rx.get_network_type();
if (type == mwx::NETWORK::LAYERED) {
; // Packet of layered tree network
}
else if (type == mwx::NETWORK::SIMPLE) {
; // Packet of NWK_SIMPLE
}
else if (type == mwx::NETWORK::NONE) {
; // Normal app (such as App_Twelite)
}
else {
; // Uninterpretable packet
}
// Mark the packet as handled, and prevent further intervention by the MWX library.
handled = true;
}
Each packet type is identified by .get_network_type()
as shown above.
mwx::NETWORK::LAYERED
: Refer to the packet information as is.mwx::NETWORK::SIMPLE
: Follow the processing ofNWK_SIMPLE
.mwx::NETWORK::NONE
: No network processing or duplicate packet handling is performed. For example, in the standard App_Twelite application, three packets including retransmissions are sent per transmission. If all packets are successfully received,on_rx_packet()
will be called three times. Usually, receiving three times does not mean the data from the 2nd and 3rd receptions is needed. You need to add processing for duplicate packets.
For examples, please refer to Act_Samples Rcv_Univsl
. It handles reception of packets with the same wireless channel and application ID but different types in TWELITE PAL, Act_samples, and App_Twelite. Additionally, duplicate check processing is provided for App_Twelite.
1.1.12 - Configuration Interface by Setting Behavior
UART0
(Serial
) internally. Input strings not used by the setting behavior are placed into a FIFO queue secured within the setting behavior, and Serial
behaves as if referring to this queue. Note that the internal behavior differs when the setting behavior is not registered.1.1.12.1 - <STG_STD>
<STG_STD>
is a configuration behavior with minimal configuration items.
Example configuration screen
[CONFIG/MY_APP:0/SID=8102ECE3]
a: (0x1234ABCD) Application ID [HEX:32bit]
i: ( 1) Device ID [1-100,etc]
c: ( 13) Channel [11-26]
o: (0x00000000) Option Bits [HEX:32bit]
[ESC]:Back [!]:Reset System [M]:Extr Menu
Serial
object and performs screen input/output in interactive mode. There is no need to explicitly write input processing in the application. Screen output from the application during the interactive mode screen is suppressed.Usage
Registration
// use twelite mwx c++ template library
##include <TWELITE>
##include <NWK_SIMPLE>
##include <STG_STD> // interactive mode
Add #include <STG_STD>
as above.
Reading with setup()
uint32_t APP_ID;
uint8_t CHANNEL;
uint8_t LID;
void setup() {
...
auto&& set = the_twelite.settings.use<STG_STD>();
// call reload() before reading values.
set.reload();
// read value
APP_ID = set.u32appid();
CHANNEL = set.u8ch();
LID = set.u8devid();
// apply them
the_twelite
<< TWENET::appid(APP_ID)
<< TWENET::channel(CHANNEL);
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << NWK_SIMPLE::logical_id(LID);
}
In most cases, reading the settings is done at an early stage in setup()
.
In the above example, first, the configuration behavior is registered by the_twelite.settings.use<STG_STD>()
.
Next, call set.reload()
to actually read data from EEPROM and interpret it. Note that it does not read automatically.
set.u32appid()
, set.u8ch()
, and set.u8devid()
retrieve the application ID setting, channel setting, and logical device ID setting, respectively. Here, the settings are stored in variables.
Then, the application ID, channel, and other values are applied using the setting values.
List of Settings
Below is the list of setting IDs (enum class E_STGSTD_SETID
) definitions.
Setting ID | Content |
---|---|
APPID | Application ID |
LOGICALID | Logical Device ID (8bit) |
CHANNEL | Channel |
CHANNELS_3 | Channel (up to 3 channels) |
POWER_N_RETRY | Power and retry count |
OPTBITS | Option 1 |
OPT_DWORD2 | Option 2 |
OPT_DWORD3 | Option 3 |
OPT_DWORD4 | Option 4 |
ENC_MODE | Encryption mode |
ENC_KEY_STRING | Encryption key (string input) |
<STG_STD>
defines representative settings and four freely usable 32bit values. These can be used freely by the user.
- Settings are not reflected just by reading from
<STG_STD>
. - Unnecessary items can be hidden.
- Item names and details can be changed.
Customizing the Configuration Behavior
Customize all items before calling .reload()
.
Application Name
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::appname("MY_APP");
...
set.reload();
The application name is displayed on the first line of the interactive mode.
[CONFIG/MY_APP:0/SID=8102ECE3]
Please specify a string pointer. Since no copy is made internally, local variables cannot be specified.
Default Values
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::appid_default(0x13579be);
set << SETTINGS::ch_default(18);
set << SETTINGS::lid_default(7);
...
set.reload();
Default values for application ID, frequency channel, and logical device ID (LID) can be changed.
Multiple Channel Setting Menu
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::ch_multi();
...
set.reload();
Specifying SETTINGS::ch_multi()
makes the channel setting multiple. When multiple settings are made, use .u32chmask()
to read the setting value.
Immediately Display the Configuration Screen
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::open_at_start();
...
set.reload();
Default values for application ID, channel, and logical ID can be changed.
Changing Item Names and Description Content
const TWESTG_tsMsgReplace SET_MSGS[] = {
{ int(E_STGSTD_SETID::OPTBITS), "Option 1",
"Please set option 1" },
{ int(E_STGSTD_SETID::OPT_DWORD2), "Option 2",
"Please set option 2\r\nOption 2 is such and such" },
{ 0xFF } // terminator
};
setup() {
auto&& set = the_twelite.settings.use<STG_STD>();
set.replace_item_name_desc(SET_MSGS);
...
You can change the item name to another one. The above example uses Japanese in UTF-8, but it may not display properly unless conditions such as terminal display are met.
This array ends with { 0xFF }
.
The first entry is the setting ID, the second is the item name, and the third is the explanation displayed during setting input. You can insert line breaks with \r
.
Determine Whether the Configuration Screen is Open
auto&& set = the_twelite.settings.use<STG_STD>();
if (!set.is_screen_opened()) {
// Processing when the configuration screen is not displayed
}
Outputting to serial during the configuration screen output may cause the screen to collapse. Confirm that the screen is not open with .is_screen_opened()
.
Deleting Items
auto&& set = the_twelite.settings.use<STG_STD>();
set.hide_items(E_STGSTD_SETID::OPT_DWORD3, E_STGSTD_SETID::OPT_DWORD4);
...
if(set.is_hidden(E_STGSTD_SETID::OPT_DWORD3) {
; // OPT_DWORD3 is hidden
}
Delete unnecessary items. .hide_items
hides unnecessary items by specifying item IDs as parameters (multiple can be specified as variadic arguments). Whether an item is hidden can be checked with .is_hidden()
.
-DSIZE_SETSTD_CUST_COMMON=48
.Methods
reload()
auto&& set = the_twelite.settings.use<STG_STD>();
set << SETTINGS::appname(APP_NAME)
<< SETTINGS::appid_default(DEF_APP_ID)
<< SETTINGS::open_at_start();
set.reload();
Reads the settings. Execute after all customizations are finished.
Methods (Data Reading)
Call the following methods to read data.
.reload()
before reading.Method | Content |
---|---|
uint32_t u32appid() | Application ID |
uint8_t u8devid() | Logical Device ID |
uint8_t u8ch() | Configured channel (11..26) |
uint32_t u32chmask() | Channel setting mask (bitmask, e.g., for 13, set bit 1UL « 13) |
uint8_t u8power() | Power setting (0..3) |
uint8_t u8retry() | Retry count |
uint32_t u32opt1() | Option 1 |
uint32_t u32opt2() | Option 2 |
uint32_t u32opt3() | Option 3 |
uint32_t u32opt4() | Option 4 |
uint8_t u8encmode() | Encryption mode (0: none, 1: enabled, 2: enabled, plaintext packet also shown) |
const uint8_t * u8enckeystr() | Get encryption key |
Applying Settings
Settings can be directly applied to the_twelite
or <NWK_SIMPLE>
objects using this object.
auto&& set = the_twelite.settings.use<STG_STD>();
...
set.reload(); // Actual reading from EEPROM happens here
the_twelite << set; // Apply settings (such as APPID)
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>();
nwk << set; // Apply settings (such as LID)
The applied settings are as follows. Items hidden by .hide_items()
are not applied.
Target | Item ID | Content |
---|---|---|
the_twelite | APPID | Reflected as TWENET::appid(value) |
CHANNEL | Reflected as TWENET::channel(value) . ※ Not applied when SETTINGS::ch_multi() is specified | |
CHANNELS_3 | Reflected as TWENET::chmask(value) . ※ Applied only as channel mask when SETTINGS::ch_multi() is specified | |
POWER_N_RETRY | Reflected as TWENET::tx_power(value) and TWENET::mac_retry_count(value) . Note: <NWK_SIMPLE> retransmission uses the same value. | |
<NWK_SIMPLE> | LOGICALID | Reflected as NWK_SIMPLE::logical_id(LID) |
POWER_N_RETRY | Reflected as NWK_SIMPLE::repeat_max(LID) |
Item IDs
Item IDs are specified in .hide_items()
and other places. These item IDs are defined in enum class E_STGSTD_SETID
.
E_STGSTD_SETID:: | Content |
---|---|
APPID | Application ID |
LOGICALID | Logical ID (0..100) |
CHANNEL | Channel |
CHANNELS_3 | Channel (multiple) |
POWER_N_RETRY | Power and retry settings |
OPTBITS | Option bits |
UARTBAUD | UART baud rate setting |
OPT_DWORD2 | Option bits 2 |
OPT_DWORD3 | Option bits 3 |
OPT_DWORD4 | Option bits 4 |
ENC_MODE | Encryption mode |
ENC_KEY_STRING | Encryption key |
Extra Menu
[ROOT MENU/BAT1/SID=810B645E]
0: CONFIG
1: EEPROM UTIL
2: H/W UTIL
[ESC]:Back [!]:Reset System
Press the M key to access the additional menu.
- CONFIG : Returns to the configuration screen
- EEPROM UTIL : Menu for EEPROM maintenance
- H/W UTIL : Menu to check hardware status
EEPROM UTIL
[EEPROM UTIL/BAT1/SID=810B645E]
r: Read sector.
R: Read ALL sectors.
e: Erase sector.
E: Erase ALL sectors.
[ESC]:Back [!]:Reset System [M]:Extr Menu
Read and erase sectors. When reading or erasing all sectors, input the uppercase “YES” (3 characters).
H/W UTIL
[H/W UTIL/BAT1/SID=810B645E]
No functionality is provided in the current version.
2 - TWELITE SDK / MWSDK (Legacy)
TWELITE SDK is a low-level toolchain for working with TWELITE.
Refer to it when maintaining legacy firmware written in C for TWELITE, exploring the mechanisms of TWELITE NET, or building highly optimized firmware.
2.1 - TWELITE SDK / MWSDK (Legacy)
See the following page for details:
3 - TWELITE Wings API / MWings
3.1 - TWELITE Wings API / MWings for 32-bit Arduinos
3.1.1 - TWELITE Wings API / MWings for 32-bit Arduinos
3.1.1.1 - List of Data Types and Procedures
Structures
BarePacket
Stores raw data extracted from the packet received by the parent device from a child device.
Data
Type | Name | Description |
---|---|---|
uint8_t* | u8Payload | Payload data converted to binary (excluding : , checksum, and CRLF ) |
uint16_t | u16PayloadSize | Byte size of the above data |
uint8_t | u8Checksum | Checksum of the above data |
Procedures
Type and Name | Description |
---|---|
uint8_t* u8From(int) | Gets payload data from the specified position onward |
uint8_t u8At(int) | Gets the payload data at the specified position as an 8-bit unsigned integer |
int8_t i8At(int) | Gets the payload data at the specified position as an 8-bit signed integer |
uint16_t u16At(int) | Gets the payload data at the specified position as a 16-bit unsigned integer |
int16_t i16At(int) | Gets the payload data at the specified position as a 16-bit signed integer |
uint32_t u32At(int) | Gets the payload data at the specified position as a 32-bit unsigned integer |
int32_t i32At(int) | Gets the payload data at the specified position as a 32-bit signed integer |
mwings::ParsedPacketBase
Abstract structure that stores parsed data received by the parent device from a child device.
Data
Type | Name | Description |
---|---|---|
uint32_t | u32SourceSerialId | Serial ID of the sender |
uint8_t | u8SourceLogicalId | Logical device ID of the sender |
uint16_t | u16SequenceNumber | Sequence number |
uint8_t | u8Lqi | LQI |
uint16_t | u16SupplyVoltage | Supply voltage (mV) |
This abstract structure defines data that is commonly used.
Structures derived from this abstract type (e.g., ParsedAppTwelitePacket
) can access the data defined here.
ParsedAppTwelitePacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the “Super Easy! Standard App”.
Data
Type | Name | Description |
---|---|---|
uint8_t | u8DestinationLogicalId | Logical device ID of the recipient |
uint8_t | u8RelayCount | Number of relays |
bool | bPeriodic | true if the packet is a periodic transmission |
bool[4] | bDiChanged | true if DI1–4 changed |
bool[4] | bDiState | true if DI1–4 are in Low state |
uint16_t[4] | u16AiVoltage | Input voltage of AI1–4 (mV) |
ParsedAppIoPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the Remote App.
Data
Type | Name | Description |
---|---|---|
uint8_t | u8RelayCount | Number of relays |
bool[12] | bDiState | true if each DI is in Low state |
bool[12] | bDiValid | true if each DI is valid |
bool[12] | bDiInterrupt | true if each DI has changed by interrupt |
ParsedAppAriaPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the Aria App (TWELITE ARIA mode).
Data
Type | Name | Description |
---|---|---|
uint32_t | u32RouterSerialId | Serial ID of the first relay device0x80000000 if not relayed (v1.2.2+) |
int16_t | i16Temp100x | Temperature ×100 (Celsius) |
uint16_t | u16Humid100x | Relative humidity ×100 (%) |
uint8_t | u8MagnetState | Magnet Event ID |
bool | bMagnetStateChanged | true if magnet sensor state changed |
Magnet Event ID
ID | Description |
---|---|
0x00 | No magnet nearby |
0x01 | North pole is nearby |
0x02 | South pole is nearby |
ParsedAppCuePacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the Cue App (TWELITE CUE mode).
Data
Type | Name | Description |
---|---|---|
uint32_t | u32RouterSerialId | Serial ID of the first relay device0x80000000 if not relayed (v1.2.2+) |
int16_t[10] | i16SamplesX | X-axis acceleration samples (mG) |
int16_t[10] | i16SamplesY | Y-axis acceleration samples (mG) |
int16_t[10] | i16SamplesZ | Z-axis acceleration samples (mG) |
uint8_t | u8SampleCount | Number of samples |
bool | bHasAccelEvent | true if there is an acceleration event |
uint8_t | u8AccelEvent | Acceleration Event ID |
uint8_t | u8MagnetState | Magnet Event ID |
bool | bMagnetStateChanged | true if magnet sensor state changed |
Acceleration Event ID
ID | Description |
---|---|
0x01 ~0x06 | Dice |
0x08 | Shake |
0x10 | Move |
Magnet Event ID
ID | Description |
---|---|
0x00 | No magnet nearby |
0x01 | North pole is nearby |
0x02 | South pole is nearby |
ParsedAppPalAmbPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the Pal App (environment sensor Pal).
Data
Type | Name | Description |
---|---|---|
uint32_t | u32RouterSerialId | Serial ID of the first relay device0x80000000 if not relayed (v1.2.2+) |
uint16_t | u16Ai1Voltage | AI1 input voltage (mV) |
int16_t | i16Temp100x | Temperature ×100 (Celsius) |
uint16_t | u16Humid100x | Relative humidity ×100 (%) |
uint32_t | u32Illuminance | Illuminance (lux) |
ParsedAppPalMotPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the Pal App (motion sensor Pal).
Data
Type | Name | Description |
---|---|---|
uint32_t | u32RouterSerialId | Serial ID of the first relay device0x80000000 if not relayed (v1.2.2+) |
uint16_t | u16Ai1Voltage | AI1 input voltage (mV) |
int16_t[16] | i16SamplesX | X-axis acceleration samples (mG) |
int16_t[16] | i16SamplesY | Y-axis acceleration samples (mG) |
int16_t[16] | i16SamplesZ | Z-axis acceleration samples (mG) |
uint8_t | u8SampleCount | Number of samples |
uint16_t | u16SamplingFrequency | Sampling frequency (Hz) |
ParsedAppPalOpenClosePacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the Pal App (open/close sensor Pal).
Data
Type | Name | Description |
---|---|---|
uint32_t | u32RouterSerialId | Serial ID of the first relay device0x80000000 if not relayed (v1.2.2+) |
uint16_t | u16Ai1Voltage | AI1 input voltage (mV) |
uint8_t | u8MagnetState | Magnet Event ID |
bool | bMagnetStateChanged | true if magnet sensor state changed |
Magnet Event ID
ID | Description |
---|---|
0x00 | No magnet nearby |
0x01 | North pole is nearby |
0x02 | South pole is nearby |
ParsedAppUartAsciiPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the serial communication app (A mode, simple format).
Data
Type | Name | Description |
---|---|---|
uint8_t | u8CommandId | Command type (response ID) |
uint8_t* | u8Data | Data |
uint16_t | u16DataSize | Data length |
ParsedAppUartAsciiExtendedPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the serial communication app (A mode, extended format).
AppUartAsciiExtendedPacketParser.h
Data
Type | Name | Description |
---|---|---|
uint32_t | u32DestinationSerialId | Destination serial ID |
uint8_t | u8CommandId | Command type (response ID) |
uint8_t* | u8Data | Data |
uint16_t | u16DataSize | Data length |
ParsedActPacket
Derived from mwings::ParsedPacketBase
Structure that stores data received by the parent device from a child device running the act app.
Data
Type | Name | Description |
---|---|---|
uint8_t | u8CommandId | Command type (response ID) |
uint8_t* | u8Data | Data |
uint16_t | u16DataSize | Data length |
mwings::CommandBase
Abstract structure that stores command data sent from the parent device to a child device.
Data
Type | Name | Description |
---|---|---|
uint8_t | u8DestinationLogicalId | Destination logical device ID |
Procedures
Type and Name | Description |
---|---|
bool isValid() | Returns true if the data is valid (pure virtual function) |
This abstract structure defines data and procedures that are commonly used.
Structures derived from this abstract type (e.g., AppTweliteCommand
) can access the data and procedures defined here.
AppTweliteCommand
Derived from mwings::CommandBase
Structure that stores command data sent from the parent device to a child device running the “Super Easy! Standard App”.
Data
Type | Name | Description |
---|---|---|
bool[4] | bDiToChange | true to change the state of each DO1-4 |
bool[4] | bDiState | true to set each DO1-4 to Low state |
bool[4] | bPwmToChange | true to change the state of each PWM1-4 |
uint16_t[4] | u16PwmDuty | Duty ratio of each PWM1-4 (0-1024) |
AppIoCommand
Derived from mwings::CommandBase
Structure that stores command data sent from the parent device to a child device running the Remote App.
Data
Type | Name | Description |
---|---|---|
bool[12] | bDiToChange | true to change the state of each O1-12 |
bool[12] | bDiState | true to set each O1-12 to Low state |
AppPalNoticeCommand
Derived from mwings::CommandBase
Structure that stores command data sent from the parent device to a child device running the Pal App (Notifier Pal).
AppPalNoticeCommandSerializer.h
Data
Type | Name | Description |
---|---|---|
AppPalNoticeColor | eColor | Lighting color |
AppPalNoticeBlinkSpeed | eBlinkSpeed | Blinking speed |
uint8_t | u8Brightness | Brightness (0-15) |
uint16_t | u16DurationInSec | Lighting duration (seconds) |
AppPalNoticeDetailedCommand
Derived from mwings::CommandBase
Structure that stores command data sent from the parent device to a child device running the Pal App (Notifier Pal) — detailed format.
AppPalNoticeDetailedCommandSerializer.h
Data
Type | Name | Description |
---|---|---|
AppPalNoticeRGBWColor | sRGBWColor | Lighting color (RGBW) |
uint8_t | u8BlinkDutyPercentage | Lighting time ratio (%) |
float | fBlinkPeriodInSec | Blinking period (seconds) |
uint16_t | u16DurationInSec | Lighting duration (seconds) |
AppPalNoticeEventCommand
Derived from mwings::CommandBase
Structure that stores command data (detailed format) sent from the parent device to a child device running the Pal App (Notifier Pal).
AppPalNoticeEventCommandSerializer.h
Data
Type | Name | Description |
---|---|---|
uint8_t | u8EventId | Event ID (0x00-0x10) |
AppUartAsciiCommand
Derived from mwings::CommandBase
Structure that stores command data (simple format) sent from the parent device to a child device running the serial communication app (A mode).
Data
Type | Name | Description |
---|---|---|
uint8_t | u8CommandId | Command type (response ID) |
uint8_t* | u8Data | Data |
uint16_t | u16DataSize | Data length |
Command data represented by AppUartAsciiCommand
does not require serialization.
Call Twelite.send()
directly as shown below:
Twelite.send(command.u8DestinationLogicalId, command.u8CommandId,
command.u8Data, command.u16DataSize);
AppPalNoticeRGBWColor
Structure that defines the lighting color (RGBW) used in AppPalNoticeDetailedCommand
.
AppPalNoticeDetailedCommandSerializer.h
Data
Type | Name | Description |
---|---|---|
uint8_t | red | R (0-15) |
uint8_t | green | G (0-15) |
uint8_t | blue | B (0-15) |
uint8_t | white | W (0-15) |
Procedures
Type and Name | Description |
---|---|
bool isValid() | Returns true if the data is valid |
uint16_t u16() | Returns a 16-bit unsigned integer with RGBW packed in order from LSB, 4 bits each |
Enumerations
AppPalNoticeColor
enum class
based on uint8_t
?
Enumeration that defines the lighting color used in AppPalNoticeCommand
.
AppPalNoticeCommandSerializer.h
Identifier | Value | Description |
---|---|---|
AppPalNoticeColor::RED | 0 | Red |
AppPalNoticeColor::GREEN | 1 | Green |
AppPalNoticeColor::BLUE | 2 | Blue |
AppPalNoticeColor::YELLOW | 3 | Yellow |
AppPalNoticeColor::PURPLE | 4 | Purple |
AppPalNoticeColor::LIGHT_BLUE | 5 | Light blue |
AppPalNoticeColor::WHITE | 6 | White |
AppPalNoticeColor::WARM_WHITE | 7 | Warm white |
AppPalNoticeBlinkSpeed
enum class
based on uint8_t
Enumeration that defines the blinking speed used in AppPalNoticeCommand
.
AppPalNoticeCommandSerializer.h
Identifier | Value | Description |
---|---|---|
AppPalNoticeBlinkSpeed::ALWAYS_ON | 0 | Always on |
AppPalNoticeBlinkSpeed::SLOW | 1 | Slow blinking |
AppPalNoticeBlinkSpeed::MEDIUM | 2 | Medium blinking |
AppPalNoticeBlinkSpeed::FAST | 3 | Fast blinking |
Other Data Types
Procedures
GetAppTweliteSerializedCommandPayloadSize()
constexpr
function ?
Returns the payload size (in bytes) of the serialized fixed-length data for AppTweliteCommand
.
Type and Name | Description |
---|---|
int GetAppTweliteSerializedCommandPayloadSize() | Returns the number of bytes |
GetAppAppPalNoticeSerializedCommandPayloadSize()
constexpr
function
Returns the payload size (in bytes) of the serialized fixed-length data for AppPalNoticeCommand
.
AppPalNoticeCommandSerializer.h
Type and Name | Description |
---|---|
int GetAppPalNoticeSerializedCommandPayloadSize() | Returns the number of bytes |
GetAppAppPalNoticeDetailedSerializedCommandPayloadSize()
constexpr
function
Returns the payload size (in bytes) of the serialized fixed-length data for AppPalNoticeDetailedCommand
.
AppPalNoticeDetailedCommandSerializer.h
Type and Name | Description |
---|---|
int GetAppPalNoticeDetailedSerializedCommandPayloadSize() | Returns the number of bytes |
GetAppAppPalNoticeEventSerializedCommandPayloadSize()
constexpr
function
Returns the payload size (in bytes) of the serialized fixed-length data for AppPalNoticeEventCommand
.
AppPalNoticeEventCommandSerializer.h
Type and Name | Description |
---|---|
int GetAppPalNoticeEventSerializedCommandPayloadSize() | Returns the number of bytes |
3.1.1.2 - Class List
3.1.1.2.1 - mwings::MWings Class
mwings::MWings
class.Twelite
object used in sketches is an instance of the mwings::MWings
class.mwings::MWings
class in your sketch. Please use the automatically initialized Twelite
object.Constructor
MWings()
Constructor. Initializes internal variables.
MWings()
Arguments
None
Destructor
~MWings()
Destructor. Releases allocated buffers.
~MWings()
Public Member Functions
begin()
Initializes TWELITE and starts it with the specified settings.
bool begin(HardwareSerial& serial,
const int indicatorPin = -1,
const int resetPin = -1,
const int programPin = -1,
const uint8_t channel = 18,
const uint32_t appId = 0x67720102,
const uint8_t retryCount = 2,
const uint8_t txPower = 3,
const int rxBufferSize = 1024,
const int timeout = 100,
const uint32_t encryptKey = 0,
HardwareSerial* debugSerial = nullptr);
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
HardwareSerial& | serial | Port communicating with TWELITE | ||
int | indicatorPin | Pin connected to status LED | 🆗 | Can be omitted with -1 |
int | resetPin | TWELITE’s RST pin | 🆗 | Can be omitted with -1 |
int | programPin | TWELITE’s PRG pin | 🆗 | Can be omitted with -1 |
uint8_t | channel | Frequency channel | 🆗 | Default is 18 |
uint32_t | appId | Application ID | 🆗 | Default is 0x67720102 |
uint8_t | retryCount | Number of retries | 🆗 | 0-9 |
uint8_t | txPower | Transmission power | 🆗 | 0-3 |
int | rxBufferSize | Size of packet reception buffer | 🆗 | Binary-based |
int | timeout | Timeout for each packet | 🆗 | Until reception completion |
uint32_t | encryptKey | Encryption key | 🆗 | Disabled if 0 , available from v1.2.3+ |
HardwareSerial* | debugSerial | Debug output port | 🆗 |
Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
end()
Initializes all internal variables.
inline void end()
Arguments
None
Return Value
None
update()
Reads the serial receive buffer and parses the ModBus ASCII format data sent from the parent device.
void update();
Arguments
None
Return Value
None
on()
<BarePacket
>
Registers a handler to process data sent from all child devices.
inline void on(void (*callback)(const BarePacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(BarePacket&) | callback | Event handler |
BarePacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppTwelitePacket
>
Super easy! Registers a handler to process data sent from standard app child devices.
inline void on(void (*callback)(const ParsedAppTwelitePacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppTwelitePacket&) | callback | Event handler |
ParsedAppTwelitePacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppIoPacket
>
Registers a handler to process data sent from remote control app child devices.
inline void on(void (*callback)(const ParsedAppIoPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppIoPacket&) | callback | Event handler |
ParsedAppIoPacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppAriaPacket
>
Registers a handler to process data sent from ARIA app (TWELITE ARIA mode) child devices.
inline void on(void (*callback)(const ParsedAppAriaPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppAriaPacket&) | callback | Event handler |
ParsedAppAriaPacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppCuePacket
>
Registers a handler to process data sent from CUE app (TWELITE CUE mode) child devices.
inline void on(void (*callback)(const ParsedAppCuePacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppCuePacket&) | callback | Event handler |
ParsedAppCuePacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppPalOpenClosePacket
>
Registers a handler to process data sent from PAL app (open/close sensor PAL) child devices.
inline void on(void (*callback)(const ParsedAppPalOpenClosePacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppPalOpenClosePacket&) | callback | Event handler |
ParsedAppPalOpenClosePacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppPalAmbPacket
>
Registers a handler to process data sent from PAL app (environment sensor PAL) child devices.
inline void on(void (*callback)(const ParsedAppPalAmbPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppPalAmbPacket&) | callback | Event handler |
ParsedAppPalAmbPacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppPalMotPacket
>
Registers a handler to process data sent from PAL app (motion sensor PAL) child devices.
inline void on(void (*callback)(const ParsedAppPalMotPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppPalMotPacket&) | callback | Event handler |
ParsedAppPalMotPacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppUartAsciiPacket
>
Registers a handler to process data (simple format) sent from serial communication app (A mode) child devices.
inline void on(void (*callback)(const ParsedAppUartAsciiPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppUartAsciiPacket&) | callback | Event handler |
ParsedAppUartAsciiPacket
, see Data and Procedures.Return Value
None
on()
<ParsedAppUartAsciiExtendedPacket
>
Registers a handler to process data (extended format) sent from serial communication app (A mode) child devices.
inline void on(void (*callback)(const ParsedAppUartAsciiExtendedPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedAppUartAsciiExtendedPacket&) | callback | Event handler |
ParsedAppUartAsciiExtendedPacket
, see Data and Procedures.Return Value
None
on()
<ParsedActPacket
>
Registers a handler to process data sent from act child devices.
inline void on(void (*callback)(const ParsedActPacket& packet))
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
void (*)(ParsedActPacket&) | callback | Event handler |
ParsedActPacket
, see Data and Procedures.Return Value
None
send()
<uint8_t*, int, uint8_t
>
Sends an arbitrary command (ModBus ASCII format) to the parent device.
inline bool send(const uint8_t* const payload,
const int payloadSize,
const uint8_t checksum)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
uint8_t* | payload | Payload | Between : and LRC | |
int | payloadSize | Payload size | ||
uint8_t | checksum | Checksum | LRC of the payload |
Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<uint8_t*, int
>
Sends an arbitrary command (ModBus ASCII format) to the parent device (checksum automatically added).
inline bool send(const uint8_t* const payload,
const int payloadSize)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
uint8_t* | payload | Payload | Between : and LRC | |
int | payloadSize | Payload size |
Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<uint8_t, uint8_t, uint8_t* int, uint8_t
>
Sends an arbitrary command (ModBus ASCII format) to the parent device.
inline bool send(const uint8_t logicalId,
const uint8_t commandId,
const uint8_t* const payload,
const int payloadSize,
const uint8_t checksum)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
uint8_t | logicalId | Destination logical device ID | ||
uint8_t | commandId | Command type | ||
uint8_t* | payload | Payload | Between : and LRC | |
int | payloadSize | Payload size | ||
uint8_t | checksum | Checksum | LRC of the payload |
Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<uint8_t, uint8_t, uint8_t* int
>
Sends an arbitrary command (ModBus ASCII format) to the parent device (checksum automatically added).
inline bool send(const uint8_t logicalId,
const uint8_t commandId,
const uint8_t* const payload,
const int payloadSize)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
uint8_t | logicalId | Destination logical device ID | ||
uint8_t | commandId | Command type | ||
uint8_t* | payload | Payload | Between : and LRC | |
int | payloadSize | Payload size |
Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<AppTweliteCommand
>
Super easy! Sends a command to operate standard app terminals to the parent device.
inline bool send(AppTweliteCommand& command)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
AppTweliteCommand | command | Command data |
AppTweliteCommand
, see Data and Procedures.Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<AppIoCommand
>
Sends a command to operate remote control app terminals to the parent device.
inline bool send(AppIoCommand& command)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
AppIoCommand | command | Command data |
AppIoCommand
, see Data and Procedures.Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<AppPalNoticeCommand
>
Sends a command to operate PAL app (notification PAL) terminals to the parent device.
inline bool send(AppPalNoticeCommand& command)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
AppPalNoticeCommand | command | Command data |
AppPalNoticeCommand
, see Data and Procedures.Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<AppPalNoticeDetailedCommand
>
Sends a command (detailed format) to operate PAL app (notification PAL) terminals to the parent device.
inline bool send(AppPalNoticeDetailedCommand& command)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
AppPalNoticeDetailedCommand | command | Command data |
AppPalNoticeDetailedCommand
, see Data and Procedures.Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<AppPalNoticeEventCommand
>
Sends a command (event) to operate PAL app (notification PAL) terminals to the parent device.
inline bool send(AppPalNoticeEventCommand& command)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
AppPalNoticeEventCommand | command | Command data |
AppPalNoticeEventCommand
, see Data and Procedures.Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
send()
<AppPalUartAsciiCommand
>
Sends a command (simple format) to operate serial communication app (A mode) terminals to the parent device.
inline bool send(AppPalUartAsciiCommand& command)
Arguments
Type | Name | Description | Optional | Remarks |
---|---|---|---|---|
AppPalUartAsciiCommand | command | Command data |
AppPalUartAsciiCommand
, see Data and Procedures.Return Value
Type | Value | Description | Remarks |
---|---|---|---|
bool | true | Success | |
false | Error |
3.2 - TWELITE Wings API / MWings for Python
3.2.1 - TWELITE Wings API / MWings for Python
3.2.1.1 - mwings module
mwings
This is a top-level module that is often used directly.
Twelite
Interface for TWELITE
Inherits:
threading.Thread
Twelite()
Twelite(port=None, rx_buffer_size=1024, timeout=100, tz=None, debugging=False)
Constructor. If a serial port is specified, it will be opened.
Parameters
Name | Type | Description |
---|---|---|
port | optional str | Serial port name: disabled if None |
rx_buffer_size | int | Size of the receive buffer in bytes |
timeout | int | Timeout between receiving packets (ms) |
tz | optional tzinfo | Timezone applied to received data: UTC if None |
debugging | bool | Debug output: enabled if True |
Exceptions
IOError
Serial port does not exist or is busy
close()
v1.0.10+
close()
Closes the serial port if it is open.
Usually, opened serial ports are automatically closed without calling close()
.
If you wish to close it explicitly, use this function or a with
statement.
Parameters
None
Return value
None
add_listener()
@overload
add_listener(event, handler)
add_listener(event, handler)
Registers a receive handler.
Parameters
Name | Type | Description |
---|---|---|
event | common.PacketType | Identifier for the receive event |
handler | Callable[[common.BarePacket], None] | Handler for the receive event (raw data) |
Callable[[common.SomeCallable], None] | Handler for the receive event (parsed data) |
Return value
None
on()
on(event)
Registers a receive handler (decorator version).
Parameters
Name | Type | Description |
---|---|---|
event | common.PacketType | Identifier for the receive event |
Return value
Type | Value | Description |
---|---|---|
Callable[[common.SomeCallable], common.SomeCallable] | - | Decorated function |
remove_all_listeners()
v1.0.9+
remove_all_listeners()
Removes all registered receive handlers.
Parameters
None
Return value
None
parse()
@overload
parse(character, use_lf=False)
parse(character, use_lf=False)
parse(character, use_lf=False)
Parses the given received data.
Parameters
Name | Type | Description |
---|---|---|
character | str | Received data character: string of length 1 |
bytes | Received data character: bytes of length 1 | |
int | Received data character: ASCII code | |
use_lf | bool | Type of newline character: LF if True |
Return value
Type | Value | Description |
---|---|---|
optional common.PacketType | common.PacketType | Parsed packet type |
None | No parsed packet |
Exceptions
RuntimeError
Serial port is specifiedValueError
Invalid character data detected
parse_line()
parse_line(line, use_lf=True)
Parses received data expressed as a single line string.
Parameters
Name | Type | Description |
---|---|---|
line | str | Received data string: a single line |
use_lf | bool | Type of newline character: LF if True |
Return value
Type | Value | Description |
---|---|---|
optional common.PacketType | common.PacketType | Parsed packet type |
None | No parsed packet |
Exceptions
RuntimeError
Serial port is specified
receive()
receive()
Parses data received on the serial port. Waits until the interpretation of one packet is complete.
Parameters
None
Return value
Type | Value | Description |
---|---|---|
common.PacketType | - | Parsed packet type |
Exceptions
RuntimeError
Serial port is not specified
run()
run()
Runs a subthread that performs reception. Overrides threading.Thread.run()
.
start()
.Parameters
None
Return value
None
send()
@overload
send(data)
send(data)
Sends commands from the serial port.
Parameters
Name | Type | Description |
---|---|---|
data | common.SomeCommand | Various command data |
common.BarePacket | Raw command data |
Return value
Type | Value | Description |
---|---|---|
bool | True | Success |
False | Failure |
Exceptions
RuntimeError
Serial port is not specified
set_timezone()
set_timezone(tz)
Sets the timezone applied to received data.
Parameters
Name | Type | Description |
---|---|---|
tz | tzinfo | Any timezone: ZoneInfo |
None | UTC |
Return value
None
start()
start()
Starts a subthread that performs reception. Overrides threading.Thread.start()
.
Parameters
None
Return value
None
Exceptions
RuntimeError
Serial port is not specified
stop()
stop()
Stops the subthread that performs reception. Waits until handler calls for remaining received data are finished. This may take several seconds.
Parameters
None
Return value
None
Exceptions
RuntimeError
Serial port is not specified
update()
update()
Parses data received on the serial port. Processes all data in the receive buffer and then immediately returns.
Parameters
None
Return value
Type | Value | Description |
---|---|---|
optional common.PacketType | common.PacketType | Parsed packet type |
None | No parsed packet |
Exceptions
RuntimeError
Serial port is not specified
timezone
@property
update()
Return value
Type | Value | Description |
---|---|---|
tzinfo | - | Timezone applied to received data |
3.2.1.1.1 - mwings.common Module
Contains data and procedures used throughout the library.
AccelEvent
Identifiers for accelerometer events
Inherits from:
enum.IntEnum
DICE_1
Dice: 1DICE_2
Dice: 2DICE_3
Dice: 3DICE_4
Dice: 4DICE_5
Dice: 5DICE_6
Dice: 6SHAKE
ShakeMOVE
MoveNONE
No event
AppPalNoticeBlinkSpeed
Identifiers for AppPal notification blink speed
Inherits from:
enum.IntEnum
ALWAYS_ON
Always onSLOW
Slow blinkingMEDIUM
Moderate blinkingFAST
Fast blinking
AppPalNoticeColor
Identifiers for AppPal notification colors
Inherits from:
enum.IntEnum
RED
RedGREEN
GreenBLUE
BlueYELLOW
YellowPURPLE
PurpleLIGHT_BLUE
Light blueWHITE
WhiteWARM_WHITE
Warm white
AppPalNoticeRGBWColor
Notification color expressed in RGBW format
Inherits from:
pydantic.BaseModel
AppPalNoticeRGBWColor()
AppPalNoticeRGBWColor(*, red=0, green=0, blue=0, white=15)
Parameters
Name | Type | Description |
---|---|---|
red | common.UInt8 | Red: 0 –0xF |
green | common.UInt8 | Green: 0 –0xF |
blue | common.UInt8 | Blue: 0 –0xF |
white | common.UInt8 | White: 0 –0xF |
You may pass a dictionary using
**
unpacking.
u16()
u16()
Returns a 16-bit RGBW representation.
Parameters
None
Returns
Type | Value | Description |
---|---|---|
common.UInt16 | - | 16-bit RGBW representation |
BarePacket
Raw packet data
Inherits from:
pydantic.BaseModel
BarePacket()
BarePacket(payload, checksum=None, logical_and_command_id=None)
Parameters
Name | Type | Description |
---|---|---|
payload | bytes | Binary payload data |
checksum | optional common.UInt8 | LRC8: Automatically calculated if None |
logical_and_command_id | optional tuple(common.UInt8, common.UInt8) | Logical device ID and command ID |
If the third argument is specified, the corresponding header in the payload is omitted.
i16_at()
i16_at(index)
Gets a signed 16-bit integer from the specified position.
Parameters
Name | Type | Description |
---|---|---|
index | int | Position in payload |
Returns
Type | Value | Description |
---|---|---|
common.Int16 | - | Numeric data |
i32_at()
i32_at(index)
Gets a signed 32-bit integer from the specified position.
Parameters
Name | Type | Description |
---|---|---|
index | int | Position in payload |
Returns
Type | Value | Description |
---|---|---|
common.Int32 | - | Numeric data |
i8_at()
i8_at(index)
Gets a signed 8-bit integer from the specified position.
Parameters
Name | Type | Description |
---|---|---|
index | int | Position in payload |
Returns
Type | Value | Description |
---|---|---|
common.Int8 | - | Numeric data |
u16_at()
u16_at(index)
Gets an unsigned 16-bit integer from the specified position.
Parameters
Name | Type | Description |
---|---|---|
index | int | Position in payload |
Returns
Type | Value | Description |
---|---|---|
common.UInt16 | - | Numeric data |
u32_at()
u32_at(index)
Gets an unsigned 32-bit integer from the specified position.
Parameters
Name | Type | Description |
---|---|---|
index | int | Position in payload |
Returns
Type | Value | Description |
---|---|---|
common.UInt32 | - | Numeric data |
u8_at()
u8_at(index)
Gets an unsigned 8-bit integer from the specified position.
Parameters
Name | Type | Description |
---|---|---|
index | int | Position in payload |
Returns
Type | Value | Description |
---|---|---|
common.UInt8 | - | Numeric data |
u8_from()
u8_from(index)
Gets a byte sequence starting from the specified index.
Parameters
Name | Type | Description |
---|---|---|
index | int | Starting index in payload |
Returns
Type | Value | Description |
---|---|---|
optional bytes | bytes | Partial byte sequence |
None | Invalid index |
CommandBase
Abstract base class for commands
Inherits from:
ABC
,pydantic.BaseModel
CommandBase()
CommandBase(*, destination_logical_id=120)
Parameters
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Logical device ID of destination |
You may pass a dictionary using
**
unpacking.
is_valid()
is_valid()
Checks if the command data is valid.
Parameters
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
CommandSerializerBase
Static abstract base class for command serializers
Inherits from:
ABC
serialize()
serialize(command)
Expands the given command into a raw byte sequence.
Parameters
Name | Type | Description |
---|---|---|
command | common.SomeCommand | A command data object |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded packet data |
None | Invalid command |
CrossSectional[T]
Tuple-like class for storing cross-sectional data at a specific time point
Inherits from:
common.FixedTuple[T]
CrossSectional[T]()
CrossSectional[T](length, elements)
Parameters
Name | Type | Description |
---|---|---|
T | common.T | Element type |
length | int | Number of elements |
elements | Iterable[T] | Element values |
Exceptions
ValueError
if the number of elements is invalid
DtypedDecimal
Abstract base class for numeric types that retain pandas dtype
attribute
get_dtype()
get_dtype()
Retrieves the corresponding pandas dtype
identifier.
Parameters
None
Returns
Type | Value | Description |
---|---|---|
str | - | dtype identifier |
FixedList[T]
A class representing a fixed-length list
Inherits from:
MutableSequence[T]
FixedList[T]()
FixedList[T](length, initial_elements)
Parameters
Name | Type | Description |
---|---|---|
T | common.T | Type of elements |
length | int | Number of elements |
initial_elements | Iterable[T] | Initial elements |
Exceptions
ValueError
if the number of elements is invalid
insert()
insert(index, value)
Inserts an element at the specified index.
Parameters
Name | Type | Description |
---|---|---|
index | int | Index to insert |
value | common.T | Element to insert |
Returns
None
Exceptions
IndexError
if the index is invalid
FixedTuple[T]
Class representing a fixed-length tuple
Inherits from:
Sequence[T]
FixedTuple[T]()
FixedTuple[T](length, elements)
Parameters
Name | Type | Description |
---|---|---|
T | common.T | Type of elements |
length | int | Number of elements |
elements | Iterable[T] | Elements |
Exceptions
ValueError
if the number of elements is invalid
Float32
Class to store a 32-bit floating point value
Inherits from:
float
,common.DtypedDecimal
Float32()
Float32(value=None)
Parameters
Name | Type | Description |
---|---|---|
value | optional float | Initial value |
Exceptions
ValueError
if the value is out of range
Float64
Class to store a 64-bit floating point value
Inherits from:
float
,common.DtypedDecimal
Float64()
Float64(value=None)
Parameters
Name | Type | Description |
---|---|---|
value | optional float | Initial value |
Exceptions
ValueError
if the value is out of range
Int16
Class to store a 16-bit integer
Inherits from:
int
,common.DtypedDecimal
Int16()
Int16(value=None)
Parameters
Name | Type | Description |
---|---|---|
value | optional int | Initial value |
Exceptions
ValueError
if the value is out of range
hex()
hex()
Returns a hexadecimal string representation.
Python’s built-in hex()
function does not accept int
subclasses. This method provides a similar interface as float.hex()
.
Returns
Type | Value | Description |
---|---|---|
str | - | Hexadecimal string (lowercase) |
Int32
Class to store a 32-bit integer
Inherits from:
int
,common.DtypedDecimal
Int32()
Int32(value=None)
Parameters
Name | Type | Description |
---|---|---|
value | optional int | Initial value |
Exceptions
ValueError
if the value is out of range
hex()
Same as in Int16
Int8
Class to store an 8-bit integer
Inherits from:
int
,common.DtypedDecimal
Int8()
Int8(value=None)
Parameters
Name | Type | Description |
---|---|---|
value | optional int | Initial value |
Exceptions
ValueError
if the value is out of range
hex()
Same as in Int16
MagnetState
Identifiers for magnet events
Inherits from:
enum.IntEnum
NOT_DETECTED
No magnetN_POLE_IS_CLOSE
N pole is closeS_POLE_IS_CLOSE
S pole is close
PacketParserBase
Static abstract base class for packet parsers
Inherits from:
ABC
is_valid()
is_valid(bare_packet)
Checks if the given bare packet is valid.
parse()
parse(bare_packet)
Parses the given bare packet.
PacketType
Identifiers for packet types
Inherits from:
enum.StrEnum
(Keep enum entries as-is, only translated names if needed)
SomeCallable
, SomeCommand
, SomeParsedPacket
, T
, Timezone
Keep these type variable and constant definitions unchanged.
TimeSeries[T]
Tuple-like class for storing time-series data
Inherits from:
common.FixedTuple[T]
TimeSeries[T]()
TimeSeries[T](length, elements)
Parameters
Name | Type | Description |
---|---|---|
T | common.T | Element type |
length | int | Number of elements |
elements | Iterable[T] | Element values |
Exceptions
ValueError
if the number of elements is invalid
UInt16
, UInt32
, UInt8
Same structure as Int16
, Int32
, Int8
respectively with class names and descriptions updated accordingly:
- Class to store a 16/32/8-bit unsigned integer
hex()
method same as above
3.2.1.1.2 - mwings.parsers Module
3.2.1.1.2.1 - mwings.parsers.app_twelite Module
Parsers for packets sent from the Extremely simple! Standard App (App_Twelite) and data structures to handle the data.
PacketParser
A static class parser that interprets packets representing data sent from the Extremely simple! Standard App.
Inherits:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given raw packet is valid.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given raw packet.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | ParsedPacket instance | Parsed data |
None | Parsing failed |
ParsedPacket
A structure to store the result of parsing packets representing data sent from the Extremely simple! Standard App.
Inherits:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, destination_logical_id=120, relay_count=0, periodic=False, di_changed=<mwings.common.CrossSectional object>, di_state=<mwings.common.CrossSectional object>, ai_voltage=<mwings.common.CrossSectional object>)
Parameters
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
destination_logical_id | common.UInt8 | Destination logical device ID |
relay_count | common.UInt8 | Relay count |
periodic | bool | Whether periodic transmission |
di_changed | common.CrossSectional[bool](4) | Digital interface change presence |
di_state | common.CrossSectional[bool](4) | Digital interface state |
ai_voltage | common.CrossSectional[common.UInt16](4) | Analog interface voltages |
You can also pass a dictionary unpacked with
**
.
In addition to the variables specified as constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation (only "python" ) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that timezone is attacheddatetime_must_be_clear(dt)
ai_voltage
: Automatically validates value rangecheck_ai_voltage(aiv)
destination_logical_id
: Automatically validates value rangecheck_destination_logical_id(lid)
Applicable field_serializer
packet_type
: Serializes enum name as is for JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as hexadecimal string for JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string for JSON etc.serialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts parsed data to a pandas DataFrame.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only when other args are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts parsed data to a dictionary.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only when other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
spread
splits common.CrossSectional[T]
type data.Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts parsed data to JSON format.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only when other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None for no newline) |
sort_keys | bool | Whether to sort keys |
spread
splits common.CrossSectional[T]
type data.Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.2 - mwings.parsers.app_io Module
Parsers for packets sent from the remote control app and data structures to store their contents.
PacketParser
Static class for a parser that interprets packets representing data sent from the remote control app.
Inherits from:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given raw packet is valid.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given raw packet.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | Data of type ParsedPacket | Parsed data |
None | Parsing failed |
ParsedPacket
Data structure to store the result of interpreting packets representing data sent from the remote control app.
Inherits from:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, relay_count=0, di_state=<mwings.common.CrossSectional object>, di_valid=<mwings.common.CrossSectional object>, di_interrupt=<mwings.common.CrossSectional object>)
Arguments
Properties inherited from the base class are also listed.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Always None because ADC is not used |
relay_count | common.UInt8 | Number of relays |
di_changed | common.CrossSectional[bool](12) | Digital interface change status |
di_state | common.CrossSectional[bool](12) | Digital interface state |
di_interrupt | common.CrossSectional[bool](12) | Digital interface interrupt status |
You can pass a dictionary unpacked with
**
.
In addition to the constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation ("python" only) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that timezone is attacheddatetime_must_be_clear(dt)
Applicable field_serializer
packet_type
: Serializes the enum name as is for JSON, etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as a hexadecimal string for JSON, etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string for JSON, etc.serialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data to a pandas DataFrame.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Include system information (only when other args are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data to a dictionary.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Include system information (only when other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
spread
is set, data of type common.CrossSectional[T]
is split.Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data to JSON format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Include system information (only when other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None for no newline) |
sort_keys | bool | Whether to sort keys |
spread
is set, data of type common.CrossSectional[T]
is split.Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.3 - mwings.parsers.app_aria Module
Parsers for packets sent from App Aria and data structures to store their contents.
PacketParser
Static class parser that interprets packets representing data sent from the Aria app
Inherits:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given raw packet is valid.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given raw packet.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | Data of type ParsedPacket | Parsed data |
None | Parsing failed |
ParsedPacket
Structure to store the result of interpreting packets representing data sent from the Aria app
Inherits:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, temp_100x=0, humid_100x=0, magnet_state=MagnetState.NOT_DETECTED, magnet_state_changed=False)
Arguments
Including inherited properties.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing time |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
router_serial_id | common.UInt32 | Serial ID of the first relay device (0x80000000 if none) v1.0.13+ |
temp_100x | common.Int16 | Temperature multiplied by 100 (°C) |
humid_100x | common.UInt16 | Relative humidity multiplied by 100 |
magnet_state | common.MagnetState | Magnet state |
magnet_state_changed | bool | Whether the magnet state has changed |
You can also pass a dictionary unpacked with
**
.
In addition to the variables specified in the constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation (only "python" ) |
mwings_version | str | MWings version (in PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that a timezone is attacheddatetime_must_be_clear(dt)
Applicable field_serializer
packet_type
: Serializes the enum name as-is for JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as a hexadecimal string for JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string for JSON etc.serialize_time_parsed(dt)
magnet_state
: Serializes the enum name as-is for JSON etc.serialize_magnet_state(magnet_state)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data to a pandas DataFrame format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only if other arguments are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data to a dictionary format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only if other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data to JSON format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only if other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None for no line breaks) |
sort_keys | bool | Whether to sort keys |
Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.4 - mwings.parsers.app_cue Module
Parsers for packets sent from the TWELITE CUE mode and data structures to store their contents.
PacketParser
Static class for parsing packets representing data sent from the Cue app (TWELITE CUE mode).
Inherits from:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given bare packet is valid.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid and parsable |
False | Invalid and unparsable |
parse()
parse(bare_packet)
Parses the given bare packet.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | ParsedPacket typed data | Parsed data |
None | Unparsable |
ParsedPacket
Structure to store the result of parsing packets representing data sent from the Cue app (TWELITE CUE mode).
Inherits from:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, sample_count=10, samples_x=<mwings.common.TimeSeries object>, samples_y=<mwings.common.TimeSeries object>, samples_z=<mwings.common.TimeSeries object>, has_accel_event=False, accel_event=AccelEvent.NONE, magnet_state=MagnetState.NOT_DETECTED, magnet_state_changed=False)
Parameters
Including properties inherited from the base class.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
router_serial_id | common.UInt32 | Serial ID of the first relay device (no relay is 0x80000000 ) v1.0.13+ |
sample_count | common.UInt8 | Number of accelerometer samples per axis |
samples_x | common.TimeSeries[common.Int16] | X-axis accelerometer samples |
samples_y | common.TimeSeries[common.Int16] | Y-axis accelerometer samples |
samples_z | common.TimeSeries[common.Int16] | Z-axis accelerometer samples |
has_accel_event | bool | Presence of accelerometer event |
accel_event | common.AccelEvent | Accelerometer event |
magnet_state | common.MagnetState | Magnet state |
magnet_state_changed | bool | Whether magnet state has changed |
You can also pass a dictionary unpacked with
**
.
In addition to the variables specified as constructor arguments, the following @computed_field
are also available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation (only "python" ) |
mwings_version | str | MWings version (in PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that a timezone is attacheddatetime_must_be_clear(dt)
Applicable field_serializer
packet_type
: Serializes the enum name as is in JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as a hexadecimal string in JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as an ISO 8601 string in JSON etc.serialize_time_parsed(dt)
accel_event
: Serializes the enum name as is in JSON etc.serialize_accel_event(accel_event)
magnet_state
: Serializes the enum name as is in JSON etc.serialize_magnet_state(magnet_state)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data to a pandas DataFrame.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only when other arguments are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data to a dictionary.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only when other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
spread
is set, time-series data of type common.TimeSeries[T]
will not be split.Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data to JSON format.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only when other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None for no newline) |
sort_keys | bool | Whether to sort keys |
spread
is set, time-series data of type common.TimeSeries[T]
will not be split.Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.5 - mwings.parsers.app_cue_pal_event Module
Parsers for packets sent from TWELITE CUE in PAL event mode (Dice/Move mode) and data structures to store their contents.
PacketParser
Static class parser that interprets packets representing data sent from the CUE app (operation PAL mode: Dice/Move mode).
Inherits from:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given raw packet is valid.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given raw packet.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | Data of type ParsedPacket | Parsed data |
None | Parsing failed |
ParsedPacket
Data structure to store the result of parsing packets representing data sent from the CUE app (operation PAL mode: Dice/Move mode).
Inherits from:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, accel_event=AccelEvent.NONE)
Arguments
Includes inherited properties as well.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
router_serial_id | common.UInt32 | Serial ID of the first relay device (no relay is 0x80000000 ) v1.0.13+ |
ai1_voltage | common.UInt16 | Voltage of AI1 (mV) |
accel_event | common.AccelEvent | Acceleration event |
You can also pass a dictionary unpacked with
**
.
In addition to the variables specified as constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation (only "python" ) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that timezone is attacheddatetime_must_be_clear(dt)
Applicable field_serializer
packet_type
: Serializes enum name as-is for JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as hexadecimal string for JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string for JSON etc.serialize_time_parsed(dt)
accel_event
: Serializes enum name as-is for JSON etc.serialize_accel_event(accel_event)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data into a pandas DataFrame format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Include system information (only if other arguments are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data into dictionary format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Include system information (only if other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
spread
is set, data of type common.CrossSectional[T]
will be split. Time-series data of type common.TimeSeries[T]
will not be split.Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data into JSON format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Include system information (only if other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None means no line breaks) |
sort_keys | bool | Whether to sort keys |
spread
is set, data of type common.CrossSectional[T]
will be split. Time-series data of type common.TimeSeries[T]
will not be split.Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.6 - mwings.parsers.app_pal_openclose Module
Parsers for packets sent from PAL App (Open/Close PAL) and data structures to store their contents.
PacketParser
Static class parser that interprets packets representing data sent from PAL App (Open/Close PAL).
Inherits from:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given raw packet is valid.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given raw packet.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | Data of type ParsedPacket | Parsed data |
None | Parsing failed |
ParsedPacket
Structure to store the result of parsing packets representing data sent from PAL App (Open/Close PAL).
Inherits from:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, magnet_state=MagnetState.NOT_DETECTED, magnet_state_changed=False)
Parameters
Properties inherited from the base class are also listed.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing time |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
router_serial_id | common.UInt32 | Serial ID of the first relay device (0x80000000 if none) v1.0.13+ |
ai1_voltage | common.UInt16 | Voltage of AI1 (mV) |
magnet_state | common.MagnetState | Magnet state |
magnet_state_changed | bool | Whether the magnet state has changed |
You can also pass a dictionary unpacked with
**
.
In addition to the constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation ("python" only) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that a timezone is attacheddatetime_must_be_clear(dt)
Applicable field_serializer
packet_type
: Serializes enum name directly for JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as hexadecimal string for JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string for JSON etc.serialize_time_parsed(dt)
magnet_state
: Serializes enum name directly for JSON etc.serialize_magnet_state(magnet_state)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data into a pandas DataFrame.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from DataFrame |
verbose | bool | Whether to include system information (only when other args are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data into a dictionary.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only when other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort by keys |
Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data into JSON format.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in JSON |
exclude | optional set[str] | Set of keys (members) to exclude from JSON |
verbose | bool | Whether to include system information (only when other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None for no newline) |
sort_keys | bool | Whether to sort by keys |
Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.7 - mwings.parsers.app_pal_amb Module
Parsers for packets sent from PAL App (Environmental PAL) and data structures to store their contents.
PacketParser
A static class parser that interprets packets representing data sent from PAL App (Environmental PAL).
Inherits from:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given raw packet is valid.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, unparsable |
parse()
parse(bare_packet)
Parses the given raw packet.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | ParsedPacket instance | Parsed data |
None | Unparsable |
ParsedPacket
A structure to store the result of parsing packets representing data sent from PAL App (Environmental PAL).
Inherits from:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, temp_100x=0, humid_100x=0, illuminance=0)
Parameters
Including properties inherited from the base class.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
router_serial_id | common.UInt32 | Serial ID of first relay device (0x80000000 if none) v1.0.13+ |
ai1_voltage | common.UInt16 | Voltage of AI1 (mV) |
temp_100x | common.Int16 | Temperature multiplied by 100 (°C) |
humid_100x | common.UInt16 | Relative humidity multiplied by 100 |
illuminance | common.UInt32 | Illuminance (lx) |
You can also pass a dictionary unpacked with
**
.
In addition to the constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation ("python" only) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applicable field_validator
source_logical_id
: Automatically validates the range of valuescheck_source_logical_id(lid)
time_parsed
: Automatically validates that timezone info is attacheddatetime_must_be_clear(dt)
Applicable field_serializer
packet_type
: Serializes the enum name as is to JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as a hexadecimal string to JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string to JSON etc.serialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data into a pandas DataFrame.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only if other args are None ) |
Returns
Type | Description |
---|---|
pd.DataFrame | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data into a dictionary.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only if other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
Returns
Type | Description |
---|---|
dict[str, Any] | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data into a JSON string.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only if other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of indentation spaces (None for no newlines) |
sort_keys | bool | Whether to sort keys |
Returns
Type | Description |
---|---|
str | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.8 - mwings.parsers.app_pal_mot Module
Parsers for packets sent from PAL App (Motion PAL) or CUE App in Motion PAL Mode (accelerometer measurement), and data structures to store the parsed information.
PacketParser
A static class parser that interprets packets representing data sent from PAL App (Motion PAL) or CUE App (Motion PAL Mode: accelerometer measurement).
Inherits:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given bare packet is valid.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given bare packet.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | ParsedPacket instance | Parsed data |
None | Parsing failed |
ParsedPacket
A data structure to store the result of parsing packets sent from PAL App (Motion PAL) or CUE App (Motion PAL Mode: accelerometer measurement).
Inherits:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, ai1_voltage=0, sample_count=16, samples_x=<mwings.common.TimeSeries object>, samples_y=<mwings.common.TimeSeries object>, samples_z=<mwings.common.TimeSeries object>, sampling_frequency=25)
Arguments
Including properties inherited from the base class.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Sequence number |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Supply voltage (mV) |
router_serial_id | common.UInt32 | Serial ID of the first relay device (0x80000000 if none) v1.0.13+ |
ai1_voltage | common.UInt16 | Voltage of AI1 (mV) |
sample_count | common.UInt8 | Number of acceleration samples per axis |
samples_x | common.TimeSeries[common.Int16] | Acceleration samples on X axis |
samples_y | common.TimeSeries[common.Int16] | Acceleration samples on Y axis |
samples_z | common.TimeSeries[common.Int16] | Acceleration samples on Z axis |
sampling_frequency | common.UInt16 | Acceleration sampling frequency |
You can also pass a dictionary unpacked with
**
.
In addition to constructor arguments, the following @computed_field
fields are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation (only "python" ) |
mwings_version | str | MWings version (in PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
Applied field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that timezone is attacheddatetime_must_be_clear(dt)
sampling_frequency
: Validates the valuecheck_sampling_frequency(freq)
Applied field_serializer
packet_type
: Serializes enum name as is for JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as hexadecimal string for JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string for JSON etc.serialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data into a pandas DataFrame.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only effective if other arguments are None ) |
Returns
Type | Description |
---|---|
pd.DataFrame | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data into a dictionary.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only effective if other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
spread
is set, common.TimeSeries[T]
time series data is not split.Returns
Type | Description |
---|---|
dict[str, Any] | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data into JSON format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only effective if other arguments are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of spaces for indentation (None for no newlines) |
sort_keys | bool | Whether to sort keys |
spread
is set, common.TimeSeries[T]
time series data is not split.Returns
Type | Description |
---|---|
str | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.9 - mwings.parsers.app_uart_ascii Module
Parsers for packets sent from the serial communication app (format mode: simplified) and data structures to store their contents.
PacketParser
Static class parser that interprets packets representing data sent from the serial communication app (format mode: simplified).
Inherits:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given bare packet is valid.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, can be parsed |
False | Invalid, cannot be parsed |
parse()
parse(bare_packet)
Parses the given bare packet.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | An instance of ParsedPacket | Parsed data |
None | Cannot parse |
ParsedPacket
Structure to hold the results of parsing packets representing data sent from the serial communication app (format mode: simplified).
Inherits:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, command_id=0, data=b'')
Parameters
Including inherited properties.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Not obtainable, always None |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Not obtainable, always None |
supply_voltage | optional common.UInt16 | Not obtainable, always None |
command_id | common.UInt8 | Command ID |
data | bytes | Data |
You can also pass a dictionary unpacked with
**
.
In addition to the constructor arguments, the following @computed_field
are available:
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation ("python" only) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
data_base64 | str | Base64 representation of the data |
data_hexstr | str | Hexadecimal string representation of the data |
data
is not included in JSON etc. Please use data_base64
or data_hexstr
.Applied field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that a timezone is attacheddatetime_must_be_clear(dt)
sampling_frequency
: Validates the valuecheck_sampling_frequency(freq)
data
: Automatically validates lengthcheck_data(data)
Applied field_serializer
packet_type
: Serializes enum name as is into JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as hex string into JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string into JSON etc.serialize_time_parsed(dt)
- ``
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts parsed data into a pandas DataFrame.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only if other args are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts parsed data into a dictionary.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only if other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts parsed data into JSON format.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in JSON |
exclude | optional set[str] | Set of keys (members) to exclude from JSON |
verbose | bool | Whether to include system information (only if other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of indentation spaces (None for no newlines) |
sort_keys | bool | Whether to sort keys |
Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.10 - mwings.parsers.app_uart_ascii_extended Module
Parsers for packets sent from the serial communication app (format mode: extended) and data structures to store their contents.
PacketParser
Static class parser for interpreting packets representing data sent from the serial communication app (format mode: extended).
Inherits from:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given bare packet is valid.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given bare packet.
Parameters
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | Instance of ParsedPacket | Parsed data |
None | Parsing failed |
ParsedPacket
Data structure to store the results of parsing packets representing data sent from the serial communication app (format mode: extended).
Inherits from:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, destination_serial_id=120, command_id=0, data=b'')
Parameters
Including inherited properties.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Not available, always None |
source_serial_id | common.UInt32 | Sender’s serial ID |
source_logical_id | common.UInt8 | Sender’s logical device ID |
lqi | common.UInt8 | Radio signal quality |
supply_voltage | optional common.UInt16 | Not available, always None |
destination_serial_id | common.UInt32 | Receiver’s serial ID |
command_id | common.UInt8 | Command ID |
data | bytes | Data |
You can also pass a dictionary unpacked with
**
.
In addition to the constructor arguments, the following @computed_field
are available.
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation ("python" only) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
data_base64 | str | Base64 representation of the data |
data_hexstr | str | Hexadecimal string representation of the data |
data
field is not included in JSON, etc. Please use data_base64
or data_hexstr
.Applicable field_validator
source_logical_id
: Automatically validates the value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that the timezone is attacheddatetime_must_be_clear(dt)
sampling_frequency
: Validates the valuecheck_sampling_frequency(freq)
data
: Automatically validates the lengthcheck_data(data)
Applicable field_serializer
packet_type
: Serializes the enum name as-is in JSON, etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as a hexadecimal string in JSON, etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string in JSON, etc.serialize_time_parsed(dt)
- ``
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts the parsed data into a pandas DataFrame.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only when other arguments are None ) |
Returns
Type | Description |
---|---|
pd.DataFrame | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not installed
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts the parsed data into a dictionary.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only when other arguments are None ) |
spread | bool | Whether to split list-like data that is not time series |
sort_keys | bool | Whether to sort keys |
Returns
Type | Description |
---|---|
dict[str, Any] | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts the parsed data into JSON format.
Parameters
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only when other arguments are None ) |
spread | bool | Whether to split list-like data that is not time series |
indent | optional int | Number of spaces for indentation (None for no line breaks) |
sort_keys | bool | Whether to sort keys |
Returns
Type | Description |
---|---|
str | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.2.11 - mwings.parsers.act Module
Parsers for packets sent from act and data structures to store their contents.
PacketParser
Static class to parse packets sent from act
Inherits:
common.PacketParserBase
is_valid()
is_valid(bare_packet)
Checks whether the given bare packet is valid.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid, parsable |
False | Invalid, not parsable |
parse()
parse(bare_packet)
Parses the given bare packet.
Arguments
Name | Type | Description |
---|---|---|
bare_packet | common.BarePacket | Raw packet data |
Returns
Type | Value | Description |
---|---|---|
optional ParsedPacket | ParsedPacket instance | Parsed data |
None | Parsing failed |
ParsedPacket
Structure to store the result of parsing packets sent from act
Inherits:
common.ParsedPacketBase
ParsedPacket()
ParsedPacket(*, time_parsed=None, packet_type=PacketType.BARE, sequence_number=None, source_serial_id=0, source_logical_id=0, lqi=None, supply_voltage=None, command_id=0, data=b'')
Arguments
Includes properties inherited from the base class.
Name | Type | Description |
---|---|---|
time_parsed | optional AwareDatetime | Parsing timestamp |
packet_type | common.PacketType | Packet type |
sequence_number | optional common.UInt16 | Not available, always None |
source_serial_id | common.UInt32 | Source serial ID |
source_logical_id | common.UInt8 | Source logical device ID |
lqi | optional common.UInt8 | Radio communication quality |
supply_voltage | optional common.UInt16 | Not available, always None |
command_id | common.UInt8 | Command ID |
data | bytes | Data |
You can also pass a dictionary unpacked with
**
.
In addition to the constructor arguments, the following @computed_field
are available:
Name | Type | Description |
---|---|---|
mwings_implementation | str | MWings implementation (only "python" ) |
mwings_version | str | MWings version (PEP440 format) |
hostname | str | Host machine name |
system_type | str | System type (e.g., "Linux" ) |
data_base64 | str | Base64 representation of the data |
data_hexstr | str | Hexadecimal representation of the data |
data
is not included in JSON or similar outputs. Use data_base64
or data_hexstr
instead.Applicable field_validator
source_logical_id
: Automatically validates value rangecheck_source_logical_id(lid)
time_parsed
: Automatically validates that timezone is attacheddatetime_must_be_clear(dt)
sampling_frequency
: Validates the valuecheck_sampling_frequency(freq)
Applicable field_serializer
packet_type
: Serializes enum name as is to JSON etc.serialize_packet_type(packet_type)
source_serial_id
: Serializes as hexadecimal string to JSON etc.serialize_source_serial_id(source_serial_id)
time_parsed
: Serializes as ISO 8601 string to JSON etc.serialize_time_parsed(dt)
to_df()
to_df(include=None, exclude=None, verbose=True)
Converts parsed data into a pandas DataFrame.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of columns (members) to include in the DataFrame |
exclude | optional set[str] | Set of columns (members) to exclude from the DataFrame |
verbose | bool | Whether to include system information (only effective if other args are None ) |
Returns
Type | Value | Description |
---|---|---|
pd.DataFrame | - | Converted DataFrame |
Exceptions
EnvironmentError
if pandas is not available
to_dict()
to_dict(include=None, exclude=None, verbose=True, spread=False, sort_keys=False)
Converts parsed data into a dictionary.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the dictionary |
exclude | optional set[str] | Set of keys (members) to exclude from the dictionary |
verbose | bool | Whether to include system information (only effective if other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
sort_keys | bool | Whether to sort keys |
Returns
Type | Value | Description |
---|---|---|
dict[str, Any] | - | Converted dictionary |
to_json()
to_json(include=None, exclude=None, verbose=True, spread=False, indent=2, sort_keys=False)
Converts parsed data into JSON format.
Arguments
Name | Type | Description |
---|---|---|
include | optional set[str] | Set of keys (members) to include in the JSON |
exclude | optional set[str] | Set of keys (members) to exclude from the JSON |
verbose | bool | Whether to include system information (only effective if other args are None ) |
spread | bool | Whether to split non-time-series list-like data |
indent | optional int | Number of indent spaces (None for no line breaks) |
sort_keys | bool | Whether to sort keys |
Returns
Type | Value | Description |
---|---|---|
str | - | Converted JSON string |
model_*()
pydantic.BaseModel
.3.2.1.1.3 - mwings.serializers Module
3.2.1.1.3.1 - mwings.serializers.app_twelite Module
mwings.serializers.app_twelite
Serializers to generate commands representing packets for the Extremely Simple! Standard App, and data structures to handle them.
CommandSerializer
Static class to generate commands representing packets for the Extremely Simple! Standard App
Inherits:
common.CommandSerializerBase
serialize()
serialize(command)
Expands the given command into a raw byte sequence.
Arguments
Name | Type | Description |
---|---|---|
command | Command | Command data |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded data |
None | Invalid command data |
Command
Structure to store data used to generate commands representing packets for the Extremely Simple! Standard App
Inherits:
common.CommandBase
Command()
Command(*, destination_logical_id=120, di_to_change=<mwings.common.FixedList object>, di_state=<mwings.common.FixedList object>, pwm_to_change=<mwings.common.FixedList object>, pwm_duty=<mwings.common.FixedList object>)
Arguments
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Destination logical device ID |
di_to_change | common.FixedList[bool](4) | Digital interfaces to change |
di_state | common.FixedList[bool](4) | Digital interface states after change |
pwm_to_change | common.FixedList[bool](4) | PWM interfaces to change |
pwm_duty | common.FixedList[int](4) | PWM interface duty after change |
You can also pass a dictionary unpacked with
**
.
pwm_duty
should be between 0
and 1024
. A value of 0xFFFF
indicates invalid.is_valid()
is_valid()
Checks whether the command data is valid.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
model_*()
pydantic.BaseModel
.3.2.1.1.3.2 - mwings.serializers.app_io Module
mwings.serializers.app_io
Serializers that generate commands representing packets to be sent to the remote control app, and the data structures to handle them.
CommandSerializer
Static class that serializes commands representing packets to be sent to the remote control app
Inherits from:
common.CommandSerializerBase
serialize()
serialize(command)
Expands the given command into a raw packet byte sequence.
Parameters
Name | Type | Description |
---|---|---|
command | Command | Command data |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded data |
None | Invalid command data |
Command
Data structure to hold data used to generate commands representing packets to be sent to the remote control app
Inherits from:
common.CommandBase
Command()
Command(*, destination_logical_id=120, di_to_change=<mwings.common.FixedList object>, di_state=<mwings.common.FixedList object>)
Parameters
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Destination logical device ID |
di_to_change | common.FixedList[bool](12) | Digital interfaces to change |
di_state | common.FixedList[bool](12) | State of digital interfaces after change |
You can also pass a dictionary unpacked with
**
.
is_valid()
is_valid()
Checks whether the command data is valid.
Parameters
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
model_*()
pydantic.BaseModel
.3.2.1.1.3.3 - mwings.serializers.app_pal_notice Module
mwings.serializers.app_pal_notice
Serializers that generate commands representing packets to be sent to the PAL App (Notification PAL), and the data structures to handle them.
CommandSerializer
A static class serializer that generates commands representing packets to be sent to the PAL App (Notification PAL).
Inherits:
common.CommandSerializerBase
serialize()
serialize(command)
Expands the given command into a raw packet byte sequence.
Arguments
Name | Type | Description |
---|---|---|
command | Command | Command data |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded data |
None | Invalid command data |
Command
A structure to store parameters used when generating commands representing packets to be sent to the PAL App (Notification PAL).
Inherits:
common.CommandBase
Command()
Command(*, destination_logical_id=120, color=AppPalNoticeColor.WHITE, blink_speed=AppPalNoticeBlinkSpeed.ALWAYS_ON, brightness=8, duration_in_sec=5)
Arguments
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Destination logical device ID |
color | common.AppPalNoticeColor | Lighting color name |
blink_speed | common.AppPalNoticeBlinkSpeed | Blinking speed |
brightness | common.UInt8 | Brightness |
duration_in_sec | common.UInt8 | Total lighting (blinking) duration in seconds |
You can pass a dictionary unpacked with
**
.
is_valid()
is_valid()
Checks whether the command data is valid.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
model_*()
pydantic.BaseModel
.3.2.1.1.3.4 - mwings.serializers.app_pal_notice_detailed Module
mwings.serializers.app_pal_notice_detailed
Serializers that generate commands representing detailed packets to be sent to the PAL App (Notification PAL), and the data structures to handle them.
CommandSerializer
Static class serializer that generates commands representing detailed packets to be sent to the PAL App (Notification PAL).
Inherits from:
common.CommandSerializerBase
serialize()
serialize(command)
Expands the given command into a raw packet byte sequence.
Parameters
Name | Type | Description |
---|---|---|
command | Command | Command data |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded data |
None | Invalid command data |
Command
Data structure for storing data used to generate commands representing detailed packets to be sent to the PAL App (Notification PAL).
Inherits from:
common.CommandBase
Command()
Command(*, destination_logical_id=120, color=AppPalNoticeRGBWColor(red=0, green=0, blue=0, white=15), blink_duty_percentage=100, blink_period_in_sec=1.0, duration_in_sec=1)
Parameters
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Destination logical device ID |
color | common.AppPalNoticeRGBWColor | RGBW color for illumination |
blink_duty_percentage | common.UInt8 | Percentage of on-time during blinking |
blink_period_in_sec | common.Float64 | Blink period in seconds |
duration_in_sec | common.UInt8 | Total duration of illumination (blinking) |
You can also pass a dictionary unpacked with
**
.
is_valid()
is_valid()
Checks whether the command data is valid.
Parameters
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
model_*()
pydantic.BaseModel
.3.2.1.1.3.5 - mwings.serializers.app_pal_notice_event Module
mwings.serializers.app_pal_notice_event
Serializers that generate commands representing event packets to be sent to the PAL App (Notification PAL), and the data structures to handle them.
CommandSerializer
Static class serializer that generates commands representing event data packets sent to the PAL App (Notification PAL)
Inherits from:
common.CommandSerializerBase
serialize()
serialize(command)
Expands the given command into a raw packet byte sequence.
Arguments
Name | Type | Description |
---|---|---|
command | Command | Command data |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded data |
None | Invalid command data |
Command
Structure to hold data used when generating commands representing event data packets sent to the PAL App (Notification PAL)
Inherits from:
common.CommandBase
Command()
Command(*, destination_logical_id=120, event_id=0)
Arguments
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Destination logical device ID |
event_id | common.UInt8 | Event ID |
You can also pass a dictionary unpacked with
**
.
is_valid()
is_valid()
Checks whether the command data is valid.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
model_*()
pydantic.BaseModel
.3.2.1.1.3.6 - mwings.serializers.app_uart_ascii Module
mwings.serializers.app_uart_ascii
Serializers that generate commands representing packets to be sent to the serial communication app (format mode: simplified), and the data structures to handle them.
CommandSerializer
Static class serializer that generates commands representing packets to be sent to the serial communication app (format mode: simplified)
Inherits from:
common.CommandSerializerBase
serialize()
serialize(command)
Expands the given command into a raw packet byte sequence.
Arguments
Name | Type | Description |
---|---|---|
command | Command | Command data |
Returns
Type | Value | Description |
---|---|---|
optional common.BarePacket | common.BarePacket | Expanded data |
None | Invalid command data |
Command
Structure to store data used to generate commands representing packets to be sent to the serial communication app (format mode: simplified)
Inherits from:
common.CommandBase
Command()
Command(*, destination_logical_id=120, command_id=0, data)
Arguments
Name | Type | Description |
---|---|---|
destination_logical_id | common.UInt8 | Destination logical device ID |
command_id | common.UInt8 | Command ID |
data | bytes | Data |
You can pass a dictionary unpacked with
**
.
is_valid()
is_valid()
Checks whether the command data is valid.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Valid |
False | Invalid |
model_*()
pydantic.BaseModel
.3.2.1.1.4 - mwings.utils Module
mwings.utils
Contains general-purpose utility functions.
ask_user()
ask_user(prompt, regex, on_error, ex_verifier=None, max_attempts=None)
Gets input from the user via the console.
Arguments
Name | Type | Description |
---|---|---|
prompt | str | Message displayed in the prompt |
regex | str | Regular expression to validate user input |
on_error | str | Message displayed when user input is invalid |
ex_verifier | optional Callable[[str], bool] | Function to further validate input string beyond regex |
max_attempts | optional int | Number of retry attempts. None means unlimited |
Returns
Type | Value | Description |
---|---|---|
str | - | Validated user input string |
ask_user_for_port()
ask_user_for_port()
Prompts the user to select a port to use.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
str | - | Selected port name |
byte_count_from()
byte_count_from(character_count)
Converts the length of a byte sequence represented as an ASCII string to the length of its binary representation.
Arguments
Name | Type | Description |
---|---|---|
character_count | int | Length of the ASCII representation of the byte sequence |
Returns
Type | Value | Description |
---|---|---|
int | - | Length of the byte sequence in binary form |
character_from()
character_from(hexvalue)
Converts a number from 0x0
to 0xF
to its hexadecimal character representation.
Arguments
Name | Type | Description |
---|---|---|
hexvalue | int | Number |
Returns
Type | Value | Description |
---|---|---|
int | - | ASCII code of character |
find_ascii()
find_ascii(port, data, timeout, debugging=False)
Waits to receive the specified ASCII string.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
data | str | ASCII string |
timeout | int | Timeout (seconds) |
debugging | bool | Debug output |
Returns
Type | Value | Description |
---|---|---|
bool | True | Reception confirmed |
bool | False | Reception not confirmed |
find_binary()
find_binary(port, data, timeout, debugging=False)
Waits to receive the specified byte sequence.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
data | str | Byte sequence |
with_terminal | bool | Whether to use terminal data |
terminal | int | Data to treat as terminal |
timeout | int | Timeout (seconds) |
debugging | bool | Debug output |
Returns
Type | Value | Description |
---|---|---|
bool | True | Reception confirmed |
bool | False | Reception not confirmed |
flush_rx_buffer()
flush_rx_buffer(port)
Clears the receive buffer.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
Returns
None
flush_tx_buffer()
flush_tx_buffer(port)
Clears the transmit buffer.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
Returns
None
get_ports()
get_ports()
Retrieves a list of available serial ports.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
list[str] | - | List of port names |
hex_from()
hex_from(character)
Converts an ASCII character representing a hexadecimal digit to its numeric value. The result is undefined for characters other than 0
-9
and A
-F
.
Arguments
Name | Type | Description |
---|---|---|
character | int | ASCII code of the character |
Returns
Type | Value | Description |
---|---|---|
int | - | Numeric value |
is_initialized()
is_initialized(port)
Checks whether the serial port is initialized.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
Returns
Type | Value | Description |
---|---|---|
bool | True | Initialized |
False | Not initialized |
is_readable()
is_readable(port)
Checks whether data can be read from the serial port.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
Returns
Type | Value | Description |
---|---|---|
bool | True | Data available in receive buffer |
False | Not readable |
is_there_some_ports()
is_there_some_ports()
Checks whether any serial ports are available.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
bool | True | Serial ports exist |
False | None available |
is_writable()
is_writable(port)
Checks whether data can be written to the serial port.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
Returns
Type | Value | Description |
---|---|---|
bool | True | Writable |
False | Not writable |
lrc8()
lrc8(data)
Calculates the 8-bit LRC.
Arguments
Name | Type | Description |
---|---|---|
data | bytes | Byte sequence to calculate |
Returns
Type | Value | Description |
---|---|---|
int | - | LRC8 value |
millis()
millis()
Gets the current system time in milliseconds.
Arguments
None
Returns
Type | Value | Description |
---|---|---|
int | - | System time (ms) |
open_on_system()
open_on_system(path)
Opens the specified file path with the system’s default application.
Arguments
Name | Type | Description |
---|---|---|
path | Path | File path |
Returns
None
write_binary()
write_binary(port, data)
Sends a byte sequence to the serial port.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
data | int | Data to send |
bytes | Sequence of data to send |
Returns
None
write_in_ascii()
write_in_ascii(port, data)
Sends an ASCII representation of a byte sequence to the serial port.
Arguments
Name | Type | Description |
---|---|---|
port | serial.Serial | Serial port |
data | int | Character to send |
bytes | String to send |
Returns
None