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>
- 1.1.13: Revision History
- 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
- 4: TWENET reference
- 4.1: TWENETmcu - Microcontroller Library
- 4.1.1: About Microcontrollers
- 4.1.2: Startup Functions main(), WarmMain()
- 4.1.3: RAM Allocation
- 4.1.4: About printf (Debugging, Serial Output)
- 4.2: TWENETmwf - Peripheral C++ Library
- 4.2.1: mwf_common
- 4.2.2: mwf_periph_common - Peripheral common
- 4.2.3: mwf_periph_adc - ADC
- 4.2.4: mwf_periph_gint - GINT(GPIO)
- 4.2.5: mwf_periph_i2c - I2C
- 4.2.6: mwf_periph_ntag - NTAG
- 4.2.7: mwf_periph_pwm - PWM, Timer
- 4.2.8: mwf_periph_rng - TRNG
- 4.2.9: mwf_periph_spi - SPI
- 4.2.10: mwf_periph_wtimer - WTIMER, FRWT
- 4.2.11: mwf_periph_wwdt - WWDT
- 4.2.12: class tick_counter - Stop Watch
- 4.2.13: mwf-utils - utils
- 4.3: TWENETutils - TWENET Utility
- 4.3.1: utils.h
- 4.3.2: Timer Library
- 4.3.3: fprintf Library
- 4.4: TWENETcmpt - AHI Compatibility Layer
- 4.4.1: AHI-Compatible Functions
- 4.4.2: ADC-Related AHI Functions and Explanations
- 4.4.3: AHI Functions and Explanations for DIO (GPIO)
- 4.4.4: AHI Functions and Explanations for Timer (PWM)
- 4.4.5: Explanation of SMBus.c,h Defining SMBUS (I2C)-Related Procedures
- 4.4.6: AHI Functions and Explanations for SPI
- 4.4.7: AHI Functions and Explanations for Random Numbers
- 4.4.8: AHI Functions and Explanations for UART
- 4.4.9: AHI Functions and Explanations for WatchDog (WDT)
- 4.4.10: AHI Functions and Explanations for WakeTimer
- 4.4.11: AHI Functions and Explanations for Onchip Temp Sensor
- 4.5: TWENETeastl - EASTL Library
- 4.6: TWENETstgs - twesettings Library
- 4.6.1: printf library
- 4.6.2: TWESTG_CMD_u32CmdOp() Command Explanation
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.
1.1.13 - Revision History
Update Method
Fixes and additions after the release of the TWELITE STAGE distribution package are stored in the GitHub repository. Please replace the distribution package location as needed for use. Other updates to MWSDK may be required. Please refer to the release notes at the time of update. For MWSDK updates, please refer here.
How to Update MWX Library Code
The library source code is published on the GitHub repository. To replace the library source code, follow the steps below.
Clone the Git repository or download the source code in zip format from the link of each release.
Replace the contents of the following folder:
.../MWSTAGE/ --- TWELITE STAGE distribution folder
.../MWSDK --- MWSDK folder
.../TWENET/current/src/mwx <-- Replace this folder
Updates Before Release
Updates before release may be posted below.
https://github.com/monowireless/mwx/wiki
History
0.2.2 (MWSDK2025_08 version)
- Added multi-app support (MULTINONE, which bundles multiple app codes into a single binary and selects one at startup).
- Added
MWX_
prefix tocbToCoNet_???
functions.- Introduced
MWX_USE_ALIAS
macro inmwx_appcore.c
. If defined, it aliases theMWX_cbToCoNet???()
callback function directly tocbToCoNet???()
to suppress redundant function calls.
- Introduced
- Modified packet queue size to
ToCoNet_USE_MOD_TXRXQUEUE_MULTINONE
. - Converted application-defined callback functions for interactive mode to function pointers (
MWX_TWEINTRCT_***
, etc.). - Changed the group of callback functions used in the MWX library to be called via function pointers.
mwx_pf_init_coldboot
,mwx_pf_setup
,mwx_pf_begin
,mwx_pf_loop
,mwx_pf_init_warmboot
,mwx_pf_wakeup
,mwx_pf_on_rx_packet
,mwx_pf_on_tx_comp
,mwx_pf_on_nwk_event
.
- Added
- Fixed inconsistency in processing before and after
setup()
as follows:- Introduced
on_setup()
method which is called just after::setup()
procedure. - Changed
on_begin()
which is always called just before::begin()
procedure. Theon_begin()
used for board behavior was calledthe_twelite.begin()
procedure in::setup()
.
- Introduced
- Improved the definitions of
mwx::G_BYTE()
,mwx::G_WORD()
, andmwx::G_DWORD()
to allow their use with r-values. - Fixed an issue where
fmt
inSerial::println(T, fmt)
did not output correctly whenDEC
orOCT
was specified. NAK
was not being sent correctly by theWire
object.- Improved
serial_parser
to allow output withSerial <<
even with r-values, as shown below:Serial << serparser_attach(PARSER::ASCII, buf.begin(), buf.size())
- Added
explicit
to theoperator bool()
method. - Renamed
mwx::S_OCTET()
tomwx::S_BYTE()
. - Introduced a predefined macro
MWX_PF_CALLBACKS_PRESENT
to check if(*mwx_pf_setup)()
,(*mwx_pf_loop)()
, etc. are supported, which should be used to ask the library to use a user-defined function instead ofsetup()
,loop()
, etc. - Added
mwx::stream::vprintfmt()
to supportva_list
parameters. - Added a procedure to initialize a serial port with external memory (for FIFO).
mwx::serial_jen::setup(uint16_t siz_buf_tx, uint8_t *pu8_buf_tx, uint16_t siz_buf_rx, uint8_t *pu8_buf_rx)
- Added
USE_IN_TWENET_C
macro tomwx_debug.h
. (An experimental attempt to use theNWK_SIMPLE
class without linking the mwx library).
0.2.1 (MWSDK2024_07G version)
- Call
on_rx_packet()
for packets without network information (NWK_SIMPLE or others, but just a plain packet). - Added energy scan feature on MWX.
* Added
on_nwk_event()
callback on MWX (passing the completion event of Energy Scan). - Added
vSMBusDeInit()
procedure to end the use of an I2C device. - [GOLD] Supported the macro definitions for saving settings in the BANK7 memory area.
*
G_TWENET_FREE_RUNNING_WTIMER_ENABLED()
*G_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
*G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
0.2.1 2023-06-29
- Fixed a bug in event handling in
app_core.c
and unified its behavior (including the fixes from 0.2.2 below).cbToCoNet_vRxEvent()
: If the event is handled by network behavior, callthe_vapp.cbToCoNet_vRxEvent()
, otherwise callon_rx_packet()
.cbToCoNet_vTxEvent()
: If the event is handled by network behavior, callthe_vapp.cbToCoNet_vTxEvent()
, otherwise callon_tx_comp()
.cbToCoNet_vNwkEvent()
: If the event is handled by network behavior, call.cbToCoNet_vNwkEvent()
, otherwise callon_nwk_event()
.
- Enabled the use of ADC5 and ADC6 for TWELITE RED.
- Fixed a bug in the mV calculation of the power supply voltage for TWELITE RED’s ADC.
- Added
settings::do_command()
. - Added the
MWX_STGS_STD_DEF_APPID
macro to explicitly set the defaultAPP_ID
for interactive modesettings
. - [GOLD] Added support for TWELITE GOLD for the MC3630 sensor driver.
- added
div100_128th()
to convert 128th value intodiv100()
style object. - [GOLD] modified
CPUCLK_XXX
defines to fit TWELITE GOLD. - [GOLD] added
mac_temp_update()
to temperature recal of MAC/RADIO when bigger change is seen. - [GOLD] added
get_on_boot_temperature()
andget_on_boot_voltage()
indiv_result_i32
object. - [GOLD] Incorporated the I2C-related library code
SMBus.[ch]
into the TWENETcmpt library. - [GOLD] In MWX, setting
g_twenet_chipsensor_auto_on_boot = 1;
now automatically acquires the chip temperature sensor data. This sensor data is used for the RF part’s initialization parameters. - fixed that
vAHI_DioWakeEdge()
is not called properly whenpinMode()
is called for two or more ports. (storing bitmap state internally in mwx codes) - fixed
attachIntDio()
detachIntDio()
to consider behavior ofvAHIDioInterruptEdge()
. - fixed that repeat count of
<NWK_SIMPLE>
is not incremented when it’s repeating.
0.2.0 - 2022-03-01
Library Name | Dependency Version |
---|---|
mwx | 0.2.0 |
twesettings | 0.2.6 |
TWENET C | 1.3.5 |
Main changes
- Changed the Wire object that allocates memory to the heap area.
- To avoid name collisions in utils.h, changed the function name from
G_OCTET()
toG_BYTE()
. - Changed the order of
vAHI_DioInterruptEnable()
inattachIntDio()
. - Added
the_twelite.network2
to support universal receivers (NWK_LAYERED
,NWK_SIMPLE
or receiving network-less packets in the same executable code). - Added
NWK_LAYERED
(currently only supports parent device reception) - Introduced the function
MWX_Set_Usder_App_Ver()
to set the application version during MWX initialization. - Added
mwx::pnew()
to simplify placement new notation. - Added EASTL support
- Added new[] operator for EASTL
- Precompiled most of the MWX source code to speed up compilation.
- Fixed an issue where DIO events were passed to unrelated ports.
0.1.9 - 2021-12-15
Library Name | Dependency Version |
---|---|
mwx | 0.1.9 |
twesettings | 0.2.6 |
TWENET C | 1.3.5 |
Main changes
- Added board support
BRD_ARIA
and sensor definitionSHT4x
for TWELITE ARIA - Added internal procedure to allow output using
Serial
class object during interactive mode (Serial._force_Serial_out_during_intaractive_mode()
)
0.1.8 - 2021-09-09
Library Name | Dependency Version |
---|---|
mwx | 0.1.8 |
twesettings | 0.2.6 |
TWENET C | 1.3.5 |
Main changes
- Definitions of
Serial1
port and alternative port were incorrect - Allowed changing the baud rate of
Serial
(UART0) - Added event callbacks to notify receiving packet (
on_rx_packet()
) and transmission completion (on_tx_comp()
)- If the callback function is not defined, the previous procedure is still available
- Fixed incorrect definition ID and some default values in
<STG_STD>
interactive mode settings - Allowed changing default values of channel and logical device ID in addition to AppID in
<STG_STD>
interactive mode settings - Allowed some settings of
the_twelite
and<NWK_SIMPLE>
objects to be done in interactive mode<STG_STD>
object - Allowed setting default retry count in
<NWK_SIMPLE>
- Disabled Serial (UART0) input/output from application while
<STG_STD>
interactive mode screen is displayed - Added
CUE::PIN_SET
,PAL???"":PIN_SET
(PIN_BTN
is unnatural to use for CUE without button) - Moved
random()
namespace to mwx:: (alias in global name) - Changed MONOSTICK watchdog setting to 32ms units
- Fixed pin initialization issue when sleeping with
BRD_TWELITE
0.1.7 - 2020-12-03
Library Name | Dependency Version |
---|---|
mwx | 0.1.7 |
twesettings | 0.2.6 |
TWENET C | 1.3.4 |
Main changes
- Added TWELITE CUE board behavior (https://mwx.twelite.info/v/v0.1.7/boards/cue).
- Added method to receive packets that are not in
NWK_SIMPLE
format (without network usage) when usingNWK_SIMPLE
. Initialize withNWK_SIMPLE::receive_nwkless_pkt()
. When using this packet info, only use the TWENET C library structure via.get_psRxDataApp()
and data array via.get_payload()
. Other methods of the received packet (auto&& rx = the_twelite.receiver.read()
) return undefined info. - Refined
get_stream_helper()
code and improved API for read/write position. - Added EEPROM class object (https://mwx.twelite.info/v/v0.1.7/api-reference/predefined_objs/eeprom)
- Sample (https://github.com/monowireless/Act_samples/tree/master/Unit_EEPROM)
- Fixed bug in
smplbuf::get_stream_helper()
- Added
pktparser
class (https://mwx.twelite.info/v/v0.1.7/api-reference/classes/pktparser) - Sample (https://github.com/monowireless/Act_samples/tree/master/Unit_PktParser)
- Provided sample to build
serparser/pktparser
on other platforms (https://github.com/monowireless/mwx/tree/master/stdio)
0.1.6 - 2020-10-09
Library Name | Dependency Version |
---|---|
mwx | 0.1.6 |
twesettings | 0.2.5 |
TWENET C | 1.3.4 |
Main changes
- Added
div100()
that calculates quotient and remainder and outputs toSerial
etc. - Changed implementation of
smplbuf<>
array class. To reduce memory usage, stopped inheritingmwx::stream
and defined separate inherited and helper classes. - Added functions
mwx_printf()
andmwx_snprintf()
- Added
the_twelite.stop_watchdog()
andthe_twelite.restart_watchdog()
- Maintained
mwx::stream
: Removedoperator bool()
. Specified timeout of0xff
disables timeout (.set_timeout(0xff)
). Added other<<
operators. - Added support for NOTICE PAL / PCA9632 (Explanation https://mwx.twelite.info/v/latest/boards/pal/pal_notice, Sample https://github.com/monowireless/Act_samples/tree/master/Unit_using_PAL_NOTICE)
- Added non-division scale functions for 8bit and 0..1000 range.
- Added division by 10, 100, 1000 (calculating quotient and remainder simultaneously)
div10()
,div100()
,div1000()
. Limits value range and uses multiplication and bit shifts. - Added methods supporting encrypted packets
packet_rx::is_secure_pkt()
: Checks if received packet is encryptedSTG_STD::u8encmode()
: Gets encryption setting in interactive modeSTG_STD::pu8enckeystr()
: Gets encryption key byte string in interactive mode
Serial1
: Default port is DIO14,15 which overlaps I2C in semiconductor specs, but since I2C usually uses these, set to DIO11(TxD), DIO9(RxD).Serial
: Optimized baud rate specification which divides by 100 for main baud rates.Serial
: Reduced proxy function storage foravailable()
,read()
to onlyvoid*
, saving 8 bytes.- Added
typedef boolean
- Network: Added encryption support.
- To enable encryption, set
NWK_SIMPLE::secure_pkt(const uint8_t*, bool = false)
. The first parameter is the encryption key, the second set totrue
allows receiving plaintext packets.
auto&& nwk = the_twelite.network.use<NWK_SIMPLE>(); nwk << NWK_SIMPLE::logical_id(0xFE) // set Logical ID. (0xFE means a child device with no ID) << NWK_SIMPLE::secure_pkt((const uint8_t*)"0123456789ABCDEF"); ;
- To enable encryption, set
- Added support for SHT3x and BME280 sensors
- Sensor: Added mechanism for legacy code (C library wrapper classes) to exchange settings and status.
- Sensor: Allowed specifying I2C address for SHT3x and BME280.
- Settings: Added
hide_items()
to remove unnecessary setting items. - Settings: Added H/W UTIL menu. Displays DI status, I2C probe, PAL EEPROM contents.
- Settings: Added encryption-related menu.
- I2C related fixes (to improve compatibility with code implemented using TwoWire class)
- Added missing NO_STOP message sending code in
requestFrom(false)
. - Added class name alias for
TwoWire
. - Prevented multiple initialization in
begin()
. - Added
setClock()
method (dummy function that does nothing). - Added
WIRE_CONF::WIRE_???KHZ
. Added major bus clock settings.
- Added missing NO_STOP message sending code in
0.1.5 - 2020-08-05
Library Name | Dependency Version |
---|---|
mwx | 0.1.5 |
twesettings | 0.2.5 |
TWENET C | 1.3.4 |
Main changes
- Added setting behavior (interactive mode feature)
- Implemented channel manager
chmgr
0.1.4 - 2020-07-29
Library Name | Dependency Version |
---|---|
mwx | 0.1.4 |
twesettings | 0.2.4 |
TWENET C | 1.3.3 |
Bulk download
MWSDK2020_07_UNOFFICIAL (ReadMe)
Main changes
- Added
delayMilliseconds()
- Added
digitalReadBitmap()
- Improved accuracy of
delay()
- Fixed issue where
Serial1
instance was not defined - Fixed issue where
Analogue
interrupt handler was not called
0.1.3 - 2020-05-29
Corresponds to MWSDK2020_05
Main changes
- Initialization of duplicate checker
duplicate_checker
was inadequate and did not remove duplicates as expected - Replaced
format()
implementation with less platform-dependent one. Also limited arguments to maximum 8. Number of arguments is limited if 64-bit arguments are included.
0.1.2 - 2020-04-24
Corresponds to MWSDK2020_04
Main changes
- Fixed initialization issues of
Timer0..4
- Changed internal processing of
mwx::format()
- Added experimental code for interactive mode support
0.1.1 - 2020-02-28
Main changes
- Fixed issue with handling of relay flags inside packets
0.1.0 - 2019-12-23
First release (included in SDL December 2019 issue)
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
4 - TWENET reference
In normal Act development, it is often not necessary to refer to it.
- This contains information intended for internal development and may not be recommended for general development use.
- Some information is still under development.
List of Reference Information for General Development
Below is a list of materials that may be referenced for general development purposes.
Development using Act (MWX C++ Library)
For development using Act (MWX library), please refer to:
Development using TWENET C (C language)
Development using TWENET C (C language), with APIs provided by semiconductor manufacturers and the TWENET library. Many TWELITE Apps are written in TWENET C.
TWENTEcmpt Library — A compatibility library for AHI functions (APIs provided by semiconductor manufacturers for BLUE/RED) implemented for TWELITE GOLD.
TWENETutils Library — Macros and library functions mainly used in TWENET C.
Other Libraries
TWENETeastl Library — EASTL template library for Act.
TWENETstgs/printf — printf library also used in Act implementations.
4.1 - TWENETmcu - Microcontroller Library
TWENETmcu - Microcontroller Library
Contains source code for basic microcontroller operations. Much of the code is copied from the JN5189 SDK and partially adapted for TWENET. It also includes the startup functions main()
and WarmMain()
that run TWENET.
- board - Hardware initialization (clock, GPIO pins, etc.)
- component - Libraries providing higher-level functionality (from SDK_X.Y.Z/components, middleware, etc.)
- framework - Higher-level libraries (from SDK_X.Y.Z/middleware/wireless/framework)
- device, startup - HAL layer for JN5189
- drivers - FSL libraries and others for peripheral operations
- libs - Library files (libXXX.a)
- main -
main()
and debug output functions like_putchar()
- printf -
printf()
library (does not use NewLib) - uMac - Contains MMAC.h
- utilities -
assert()
and debug functions likePRINTF()
Technical Documentation
This section describes implementation details of TWENET and considerations for developing application programs.
4.1.1 - About Microcontrollers
About Microcontrollers
The microcontroller used in TWELITE GOLD is an ARM CortexM4 core with IEEE802.15.4. TWELITE BLUE/RED use an OpenRISC core, which is a completely different microcontroller, and there are several points to note.
- While we have described content that requires special attention in terms of specifications, deeper information may be needed depending on the system and hardware requirements you are creating. For more details, please refer to the NXP JN5189 datasheet.
About the descriptions in this document
- This document mainly describes the differences from the usage with TWELITE BLUE/RED, but please refer to the JN5189 datasheet as the primary source.
- When expressing pin numbers, PIO indicates the original number of the microcontroller, while DIO/DO indicates the pin names used in TWELITE BLUE/RED. ADC1 and ADC2 are used in the same way depending on the context.
- To facilitate the porting of applications, we provide the “AHI subset” library. This library is intended for porting some of the applications we have implemented. Therefore, the behavior may differ from the API on TWELITE BLUE/RED.
Microcontroller Differences
- TWELITE BLUE/RED are big-endian, but TWELITE GOLD is little-endian.
- The ARM CortexM4 is an architecture with flexible clock configuration. As a general rule, the microcontroller’s operating clocks are 12MHz/32MHz/48MHz, and IO (such as PWM) operates at 32MHz. The main clocks for TWELITE BLUE/RED are 16MHz/32MHz, and the IO is 16MHz.
- There are restrictions on using GPIO interrupts per pin. You can use GINT (Group Interrupts) to generate an interrupt when each pin changes.
- This is implemented in the AHI subset. Since it is intended for porting our application code, it is not a comprehensive implementation, and some specifications and behaviors may differ.
- In the GINT implementation, interrupts are always generated on both edges.
- For example, if you have a pin that you want to set to a falling edge and its initial state is LOW. If the pin state transitions from LOW -> HIGH -> LOW, an interrupt will be generated for both LOW -> HIGH and HIGH -> LOW.
- While the microcontroller is running, the AHI subset suppresses the former, but when used for waking from sleep, software cannot suppress it, and it will wake up at the timing of the LOW -> HIGH transition.
- Conversely, both edges can be detected, which was not possible with TWELITE BLUE/RED, and this is also reflected in the AHI subset (
vAHI_DioInterruptEdge()
,vAHI_DioWakeEdge()
).
- There is a PINT function as an interrupt function for each pin. The maximum number of pins that can be used with PINT is fixed.
- This function is not used in the AHI subset and there are no special procedures for its combined use.
Microcontroller Functions
- It has a built-in RTC. While TWELITE BLUE/RED could improve timer accuracy by connecting an external oscillator, TWELITE GOLD has a built-in 32kHz oscillator and an RTC function.
- A circuit for floating-point arithmetic is not included. Calculations are performed by a software library, as before. However, the Cortex-M4 has a DSP function that uses fixed-point arithmetic, so using this is also an option.
Module Differences
- TWELITE RED/BLUE had a total of 24 pins, including 20 DIO pins, 2 dedicated SPI pins, and 2 dedicated analog pins. In contrast, TWELITE GOLD has 22 pins: 16 dedicated digital pins and 6 shared digital-analog pins. This means that two pins are shared on TWELITE GOLD.
- PIO0 is shared with DO0 (SPICLK) and DIO11.
- PIO14 is shared with ADC2 (Vref) and DIO8.
- In the AHI subset, you must set DIO8 to a digital port before using it.
- While the DIO pins on TWELITE BLUE/RED were in a high-impedance, pull-up state at reset, the state of each pin on TWELITE GOLD is different. In the AHI subset, DIO0..19 and DO0,1 are set as input and pull-up at initialization, while ADC1,2 are set as analog inputs.
Pins that require careful handling
For details, refer to the JN518x datasheet.
- PIO=5 (ISP_ENTRY): Similar to TWELITE BLUE/RED, when this pin is in a LOW state at reset, it enters a mode for firmware writing, etc.
- PIO=4 (ISE_SEL): When ISP_ENTRY is enabled, the subsequent behavior is changed. If it is not set to a HIGH level during firmware writing, firmware cannot be written.
- PIO=10, 11: These are mainly intended for I2C use, so they differ from other pins that can be used for GPIO. Specifically, there is no pull-up/down setting.
About Peripherals
Please refer to the documentation for the TWENETmwf (which organizes major functions through peripheral procedures) and TWENETcmpt libraries (intended for porting code using AHI).
4.1.2 - Startup Functions main(), WarmMain()
Startup Functions main(), WarmMain()
This document describes the firmware startup and callback functions for TWELITE GOLD.
main(), WarmMain()
In TWELITE GOLD, the firmware starts from the main()
function. A wake-up from sleep is handled by the WarmMain()
function. Since these functions have a weak
attribute, users can define their own versions.
__attribute__((weak)) int main(void);
__attribute((weak)) void WarmMain(void);
int main(void) {
ToCoNet_vInit_Cold_Pre();
ToCoNet_vBoard_Init(FALSE);
ToCoNet_vInit_Cold(0, 0);
ToCoNet_vMain(NULL);
}
void WarmMain(void)
{
vAHI_OnWakeup_MW(FALSE);
ToCoNet_vInit_Warm_Pre();
ToCoNet_vBoard_Init(TRUE);
ToCoNet_vInit_Warm(0);
ToCoNet_vMain(NULL);
}
// source/twenet_main.c
Call flow for a cold boot (power-on, reset)
main()
ToCoNet_vInit_Cold_Pre() <= Memory initialization
Call cbAppColdStart(FALSE) for TWENET C, init_cold() for MWX
ToCoNet_vBoard_Init(FALSE)
vAHI_RegEvMgr_MW() <= Initialize mwf library
BOARD_InitBootPins()
BOARD_InitPins() <= Initializes each pin in this function
BOARD_BootClockRUN() <= Clock initialization
vAHI_FRWTStart_MW() <= Start FRWT (WTIMER)
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
<= Preparation for on-chip temperature sensor acquisition
GPIO_PortInit() <= GPIO initialization
checkIrqPending() <= Clear interrupt status
AES_Init() <= AES encryption initialization
__enable_irq() <= Start interrupts
ToCoNet_vInit_Cold() <= TWENET initialization
Call cbAppColdStart(TRUE) for TWENET C, setup() for MWX
ToCoNet_vMain() <= TWENET main loop
Call flow for a warm boot (wake-up from RAM retention sleep)
WarmMain()
vAHI_OnWakeup_MW(FALSE) <= Peripheral processing immediately after wake-up
ToCoNet_vInit_Warm_Pre() <= Call cbAppWarmStart(FALSE) for TWENET C, init_warm() for MWX
ToCoNet_vBoard_Init(TRUE)
BOARD_BootClockRUN() <= Clock initialization
vAHI_FRWTSetBootCount_MW() <= Save FRWT (WTIMER) wake-up count
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
<= Preparation for on-chip temperature sensor acquisition
GPIO_PortInit() <= GPIO initialization
vAHI_OnWakeup_MW() <= Wake-up processing
checkIrqPending() <= Clear interrupt status
AES_Init() <= AES encryption initialization
__enable_irq(); <= Start interrupts
ToCoNet_vInit_Warm() <= TWENET initialization
Call cbAppWarmStart(TRUE) for TWENET C, wakeup() for MWX
ToCoNet_vMain() <= TWENET main loop
Call flow for wake-up from RAM OFF sleep
main()
vAHI_OnWakeupRamOff_MW(FALSE) <= Peripheral processing (checking DIO state)
ToCoNet_vInit_Cold_Pre() <= Memory initialization
Call cbAppColdStart(FALSE) for TWENET C, init_cold() for MWX
ToCoNet_vBoard_Init(FALSE)
vAHI_RegEvMgr_MW() <= Initialize mwf library
BOARD_BootClockRUN() <= Clock initialization
vAHI_FRWTStart_MW() <= Start FRWT (WTIMER)
G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
<= Preparation for on-chip temperature sensor acquisition
GPIO_PortInit() <= GPIO initialization
vAHI_OnWakeupRamOff_MW(TRUE) <= Peripheral processing (releasing GPIO RETENTION)
checkIrqPending() <= Clear interrupt status
AES_Init() <= AES encryption initialization
__enable_irq() <= Start interrupts
ToCoNet_vInit_Cold() <= TWENET initialization
Call cbAppColdStart(TRUE) for TWENET C, setup() for MWX
ToCoNet_vMain() <= TWENET main loop
ToCoNet_vBoard_Init(bool_t)
__attribute__((weak)) void ToCoNet_vBoard_Init(bool_t bWarm);
// source/twenet_main.c
This function performs hardware initialization at startup. Since it has a weak attribute, you can define your own initialization procedures. Refer to the twenet_main.c
source code for details.
This series of initialization steps includes the necessary corrections for projects generated by the MCUXpresso project wizard. For function structures and other details, please read through the code, referring to the SDK documentation.
If you need to perform unique hardware initialization, you’ll be modifying this section. Be aware that this is a sensitive part of the code, so careful modification and thorough testing are required.
ToCoNet_vInitCold(uint32)
void ToCoNet_vInit_Cold(uint32 flag, uint32 u32SysHz)
This function performs the TWENET initialization procedure.
Parameter | Description |
---|---|
flag | Startup specification. Please use 0 for normal use. |
u32SysHz | Specifies the SysTick timer frequency. Please use 0 for normal use.If needed, specify a multiple of 1000. |
ToCoNet_vInit_Warm()
void ToCoNet_vInit_Warm(uint32 flag)
This function performs the TWENET initialization procedure when waking up from sleep.
Parameter | Description |
---|---|
flag | Startup specification. Please use 0 for normal use. |
ToCoNet_vMain()
void ToCoNet_vMain(PR_TOCONET_MAIN_HOOK fp_hook)
This is the main loop for TWENET.
checkIrqPending()
static bool_t checkIrqPending();
uint64_t g_twenet_irq_bm_on_boot;
WEAK bool_t __twenet_irq_handler_pending_on_boot(int32_t);
This function saves and clears interrupt information that occurred during or after sleep, until this function is called.
- Each bit of
g_twenet_irq_bm_on_boot
corresponds to an interrupt source (IRQ_Type
) in the form(1uul << IRQ_Type)
. - The interrupt types are defined in
typedef enum IRQn
inJN5189.h
. - Interrupts are cleared by calling
NVIC_ClearPendingIRQ()
. - If a user defines the
__twenet_irq_handler_pending_on_boot(int32_t IRQ_Type)
function and theIRQ_Type
interrupt is enabled, this function will be called. If the return value isFALSE
,NVIC_ClearPendingIRQ(IRQ_Type)
is executed. If it’sTRUE
, nothing happens.
System Timer Cycle
You can set the SysTick timer cycle in the following ways:
Set it in the
ToCoNet_vInitCold()
function. This setting takes precedence.Set
G_TWENET_SYSTICK_HZ()
incbAppColdStart(FALSE)
.If neither of the above methods is used, the value of
sToCoNet_AppContext.u16TickHz
will be used.
Please note the following:
- The TWENET processing cycle (
sToCoNet_AppContext.u16TickHz
) has a maximum of 1000Hz.- The SysTick cycle is an integer multiple of
sToCoNet_AppContext.u16TickHz
.
- The SysTick cycle is an integer multiple of
- The standard setting is SysTick = 1000Hz,
sToCoNet_AppContext.u16TickHz
= 1000Hz.- A semi-standard setting is SysTick = 2000Hz or 4000Hz, and
sToCoNet_AppContext.u16TickHz
= 1000Hz. This helps distribute the load by performing some background processing (like UART) outside of the TWENET cycle. This also allows for processing with a faster SysTick timer interrupt (seeAppQAPI_SysTick_Hnd_Reg()
). - Another semi-standard setting is SysTick = 250Hz,
sToCoNet_AppContext.u16TickHz
= 250Hz. This is used for power saving or when processing per timer is heavy, as the time per radio packet is about 2-5ms (transmission time after modulation and gaps between packets). - We do not confirm the operation of each API or our applications with semi-standard settings. If you need to use them, please perform thorough testing.
- A semi-standard setting is SysTick = 2000Hz or 4000Hz, and
Initialization
G_TWENET_B_MAC_ALWAYS_RESET_ON_WAKE()
bool_t G_TWENET_B_MAC_ALWAYS_RESET_ON_WAKE()
// Macro definition
Setting this variable to 1
will re-initialize the MAC layer when waking up from sleep. This re-initialization adds extra processing time (approximately 400µs at 32MHz).
- Even with this option enabled, the pre-sleep process (saving the MAC layer state, about 100µs at 32MHz) will still be executed the same way as when the option is disabled.
4.1.3 - RAM Allocation
TWENETmcs/linker/linkscripts
.RAM Allocation
The SRAM area of TWWLIET GOLD is as follows.
BASE | TOP (End + 1) | SIZE | |
---|---|---|---|
SRAM11 | 0x0402_C000 | 0x0403_0000 | 16KB |
SRAM10 | 0x0402_8000 | 0x0402_C000 | 16KB |
SRAM9 | 0x0402_4000 | 0x0402_8000 | 16KB |
SRAM8 | 0x0402_0000 | 0x0402_4000 | 16KB |
SRAM7 | 0x0401_5000 | 0x0401_6000 | 4KB |
SRAM6 | 0x0401_4000 | 0x0401_5000 | 4KB |
SRAM5 | 0x0401_2000 | 0x0401_4000 | 8KB |
SRAM4 | 0x0401_0000 | 0x0401_2000 | 8KB |
SRAM3 | 0x0400_C000 | 0x0401_0000 | 16KB |
SRAM2 | 0x0400_8000 | 0x0400_C000 | 16KB |
SRAM1 | 0x0400_4000 | 0x0400_8000 | 16KB |
SRAM0 | 0x0400_0000 | 0x0400_4000 | 16KB |
TWENET defines the memory map as follows.
BASE | TOP | Size | Purpose | RET | Bank Name | |
---|---|---|---|---|---|---|
Application Use | 0x0400_0000 | Decided at compile time | ~64KB | Required for MMAC linking | 〇 | SRAM0..3 |
Heap | 0x0401_5000 (Changeable) | 0x0401_5C00 | 3KB | Heap area (malloc, new) | 〇 | SRAM7 |
Unused | 0x0402_0000 | 0x0402_C000 | 48KB | Unused area | SRAM8, 9, 10 SRAM11 | |
Unused | 0x0402_C000 | 0x0402_F000 | 12KB | Unused area | SRAM11 | |
Stack | 0x0402_F000 | 0x0403_0000 | 4KB | Stack area | SRAM11 | |
(BASE: Start Address, TOP: End Address + 1, RET: RAM Retention during sleep)
- The application use area is a static memory range determined at compile time. The end address can be referenced with
(uint32)&_end_fw_retention
. When sleeping, the system is set not to retain unnecessary banks based on the end address. - The heap area is a region allocated by
malloc()
and thenew
operator. Generally, repeated allocation and deallocation of this area can lead to fragmentation issues, so you should be mindful of this when implementing your application. The default setting allocates memory to SRAM bank 7. However, the last 512 bytes of bank 7 are reserved by the microcontroller’s semiconductor specifications, and the subsequent 512 bytes are reserved by TWENET.- This area can be adjusted by writing
HEAP_START=0x04014000;
andHEAP_SIZE = 8192 - BANK7_RESERVE;
inApp_User_Defs.ld
(placed directly in the build directory).HEAP_START
is the start address of the heap, andHEAP_SIZE
is the allocated size. Here are some typical combinations:- 0x04014000, 8192-BANK7_RESERVE (7KB, BANK6-7)
- 0x04012000, 16384-BANK7_RESERVE (15KB, BANK5-7)
- 0x04010000, 24576-BANK7_RESERVE (23KB, BANK4-7)
- 0x0, 0 (set the maximum area, i.e., from
_end_fw_rentention
to 0x04016000-BANK7_RESERVE, as the HEAP)
- This area can be adjusted by writing
- The unused areas are SRAM8, 9, and 10, each with 16KB.
- The stack area is set to the last 4096 bytes of SRAM11 (
0x0403_0000
) by default.- You can change the size of this area by writing
STACK_SIZE = 8192;
inApp_User_Defs.ld
(placed directly in the build directory). You can also specify the end address, such asSTACK_TOP = 0x04024000;
. - Please check
_vStackTop
and__StackLimit
in the map file created in the build directory. - This area is not retained during sleep.
- You can change the size of this area by writing
I’ve translated the text and formatted it as plain text to avoid the issue you mentioned earlier.
Setting the Retention Area during Sleep
The TWENET library is pre-configured to properly retain the necessary SRAM banks for the application use and heap areas during sleep. However, depending on the design and implementation of your application, you may want to retain banks that are not normally held. To do this, you can set the corresponding bits for any additional banks you need in the global variable G_TWENET_POWER_DOWN_RETENTION_CONFIG_ADD()
defined in the TWENETcmpt library.
For example, if you want to retain 32KB of banks 8 and 9, specify the following before calling ToCoNet_vSleep()
in the TWENET C library or the_twelite.sleep()
in the mwx library.
G_TWENET_POWER_DOWN_RETENTION_CONFIG_ADD() = PM_CFG_SRAM_BANK8_RET | PM_CFG_SRAM_BANK9_RET;
Note: Increasing the amount of retained SRAM will also increase the sleep current.
App_User_Defs.ld
Configuration Examples
If not specified, the HEAP will be from 0x0401_5000
to 0x0401_5FE0
, and the STACK will be from 0x0402_F000
to 0x0403_0000
. Below are examples for the .../build/App_User_Defs.ld
configuration.
- To allocate the maximum possible HEAP, from
_end_fw_retention
to0x0401_5FE0
:
HEAP_START = 0;
HEAP_SIZE = 0;
- To allocate HEAP in RAM6 and 7 (approx. 8KB):
HEAP_START = 0x04014000;
HEAP_SIZE = 8192 - BANK7_RESERVE;
- To set the HEAP from
_end_fw_retention
to0x0401_5000
and the STACK from0x0401_5000
to0x0401_5FE0
. (This makes BANK8..11 from0x0402_0000
to0x0403_0000
an unused area):
HEAP_TOP = 0x04015000;
HEAP_START = 0;
HEAP_SIZE = 0;
STACK_TOP = 0x04015fe0;
STACK_SIZE = 4096-BANK7_RESERVE;
Note: If both HEAP_START
and HEAP_SIZE
are 0, you can set HEAP_TOP
. In this case, HEAP_TOP
cannot be set to a region equal to or greater than 0x0402_0000
.
- To allocate 64KB for the HEAP from
0x0402_0000
and move the STACK area to a region below0x04015fe0
:
HEAP_START = 0x04020000;
HEAP_SIZE = 0x10000;
STACK_TOP = 0x04015fe0;
STACK_SIZE = 4096-BANK7_RESERVE;
OneTime_Heap.c,h
TWENETutils provides a One Time Heap for sequential memory allocation without deallocation. This makes it easy to use unused areas.
#include <OneTimeHeap.h>
OTHEAP_tsContext scOTHeap;
void setup() {
uint32 u32bytes;
void *p;
// Use the 16KB region from 0x0402_0000 to 0x0402_4000.
OTHEAP_Init(&scOTHeap, 0x04020000, 0x04024000, NULL);
Serial << crlf << "--- One Time HEAP ---";
Serial << crlf << format("start %08x", (uint32)OTHEAP_pvGetRegionStart(&scOTHeap));
Serial << crlf << format("top %08x", (uint32)OTHEAP_pvGetRegionTop(&scOTHeap));
// Allocate 100 bytes
u32bytes = 100;
Serial << crlf;
Serial << crlf << format("head %08x", (uint32)OTHEAP_pvGetHead(&scOTHeap));
p = OTHEAP_pvAlloc(&scOTHeap, u32bytes, TRUE);
// p=0x0402_0004 (The area after the 4-byte header is available)
Serial << crlf << format("alloc %dbytes [%08x->%08x)", u32bytes, (uint32)p, (uint32)p+u32bytes);
if(p) Serial << crlf << format("next %08x", *(uint32*)((uint32)p - 4));
// The header is the address of the next block (0x0402_0068)
// Allocate 10 bytes (actually 12 bytes because it's aligned to a 4-byte boundary)
u32bytes = 10;
Serial << crlf;
Serial << crlf << format("head %08x", (uint32)OTHEAP_pvGetHead(&scOTHeap));
p = OTHEAP_pvAlloc(&scOTHeap, u32bytes, TRUE);
// p=0x0402_006c
Serial << crlf << format("alloc %dbytes [%08x->%08x)", u32bytes, (uint32)p, (uint32)p+u32bytes);
if(p) Serial << crlf << format("next %08x", *(uint32*)((uint32)p - 4));
// The header is the address of the next block (0x0402_0078)
// Free the last allocated block. The address of the freed block (p=0x0402_006c)
p = OTHEAP_pvFreeLastBlock(&scOTHeap);
}
4.1.4 - About printf (Debugging, Serial Output)
printf
(debugging, serial output).About printf (Debugging, Serial Output)
printf Library
This is the printf()
process used within the TWENET library. For more details, please refer to TWENETmuc/printf.
PRINTF for Debugging
The PRINTF()
macro in the fsl library provided by NXP is used for debug output and is excluded from compilation during release. The TWENET library has also been adjusted to use PRINTF()
, but it doesn’t have all the features of the fsl library.
- The
PRINTF()
macro callsprintf_()
mentioned above. - Input macros like
GETCHAR()
are not supported.
With JN518x SDK 2.6.3 and 2.6.4, NewLib and NewLibNano show garbled or missing data in output and do not behave as expected (this is likely a buffering issue. RedLib does not show this problem, but it cannot be used in a mixed C/C++ project). For this reason, the PRINTF()
macro has been changed to use the printf_()
function within libTWENETmcu/printf.
SDK_DEBUGCONSOLE Definition
The behavior of the PRINTF()
in your application will change based on the value of SDK_DEBUGCONSOLE
.
Value | Description |
---|---|
0 | Output is sent to the debug console (Semihosting). This process is very slow. * To enable this output, you must set SDK_DEBUGCONSOLE=0 in the libTWENETmcu (Debug build), rebuild the library, and periodically call _putchar(-1) (approximately every 16ms) in your application code. (See SysTick_Handler() defined in the sample Samp_bare_MMAC ) |
1 | This is the setting for a Debug build. PRINTF uses the printf_ function (libTWENETmcu). If _putchar() is not redefined, SERIAL_bTxChar(0, c); is called. This is also the default setting for Debug builds of TWENETxxx libraries. |
2 | This is the setting for a Release build. PRINTF is excluded from compilation, and printf_() outputs nothing. If you want to use printf_() , you must redefine _putchar(int) . This is also the default setting for Release builds of TWENETxxx libraries. |
- The
_putchar()
in the libTWENETmcu library has a weak link specification. The_putchar()
you define in your application code will take precedence. - To enable
PRINTF()
within the TWENETxxx library, you must set the sameSDK_DEBUGCOSOLE
definition in your application and rebuild the library.
About SWO
TWENETmcu/source includes code for SWO output. While we don’t officially support this feature, here’s a breakdown of its code and functionality:
- Code related to SWO is defined with
-DDEBUG
and-DSERIAL_PORT_TYPE=1
. When these are set, thePRINTF()
output is adjusted to be sent to the SWO ITM (main/retarget_itm.c
,main/retarget_putchar.c
). - The SWO port is set to PIO14.
- Debugging often fails to start when SWO is enabled. Keeping the ISP pin (PIO5) in a LOW state until just before the debugger starts can sometimes resolve this.
4.2 - TWENETmwf - Peripheral C++ Library
TWENETmwf - Peripheral C++ Library
This is a simplified C++ class for handling microcontroller peripheral procedures.
Pre-defined objects are available (e.g., mwf::the_i2c0
for I2C0), and you access their functions through these objects. The pre-defined objects are smart pointers using std::unique_ptr<>
, and their actual instances are created upon first initialization.
This library’s pre-defined objects include procedures for before and after sleep, allowing you to perform pre-sleep and wake-up processing in a single step.
About Peripheral Objects
Many peripherals have integrated initialization and other procedures. This library manages them as class objects, from their creation to their destruction.
All class objects are smart pointers using std::unique_ptr<>
. Before an object is created, it’s a nullptr
, so no access is possible (it will likely cause a hang-up from a null pointer access). Always check for nullptr
before using an object.
if (the_adc) { // Check for nullptr first
the_adc->enable((1UL << 0) | (1UL << 1));
the_adc->start();
}
Pre-defined Peripheral Class Objects
Object Name | Description |
---|---|
the_adc | Use the Analog-to-Digital Converter (ADC) |
the_gpio | Use General Purpose IO (GPIO) interrupts. (The class object is not used if you don’t need interrupts) |
the_i2c0 | Use the I2C bus. (I2C0 only) |
the_ntag | Use the EEPROM for NTAG |
the_pwm[0..9] | Use PWM0..9 |
the_rng | Random number generation library |
the_spi1 | Use the SPI bus (SPI1 only) |
the_wtimer | Use the wake-up timer |
the_wwdt | Use the watchdog timer |
About the Libraries
Object Name | Description |
---|---|
mwf_common | Common definitions, base class definitions for peripheral objects |
mwf_periph_common | Common definitions, procedures for pin operations |
mwf_periph_adc | Procedures for using the ADC |
mwf_periph_gint | General Purpose IO (GPIO) interrupts |
mwf_periph_i2c | Use the I2C bus. (I2C0 only) |
mwf_periph_ntag | Use the EEPROM for NTAG |
mwf_periph_pwm | Use PWM0..9 |
mwf_periph_rng | Random number generation library |
mwf_periph_spi | Use the SPI bus (SPI1 only) |
mwf_periph_wtimer | Use the wake-up timer |
mwf_periph_wwdt | Use the watchdog timer |
About Namespaces
In principle, classes and functions are defined within the following namespaces:
mwf::
mwf::periph::
4.2.1 - mwf_common
mwf_common
Defines common definitions and base classes for peripheral classes.
Macros
BEGIN_CRITICAL
, END_CRITICAL
(Disable Interrupts)
#define BEGIN_CRITICAL { uint32_t __TWENET_regPrimask = DisableGlobalIRQ();
#define END_CRITICAL() EnableGlobalIRQ(__TWENET_regPrimask); }
// Example
extern volatile int critical_value;
void some_func() {
...
// The following is a critical section
BEGIN_CRITICAL
{
critical_value++;
}
END_CRITICAL();
}
These macros are used to set a disabled interrupt section. While they simply call DisableGlobalIRQ()
and EnableGlobalIRQ()
, they are defined as a macro similar to the do {...} while()
construct to simplify the syntax, which can seem complex due to the need for a local variable.
In the example above, if critical_value
is a value that might be changed by an interrupt handler, this procedure safely updates the value within the application’s processing.
- This macro can only be used in C++ code.
Constants, Enumerations, etc.
enum class ID_SYSHAND
Defines IDs to identify peripheral class objects.
class sys_ev_handler
A high-level (abstract) class that defines an interface to standardize procedures for sleep and wake-up.
on_sleep()
Describes the peripheral’s procedures before sleep.
on_wakeup(bool init_2nd)
Describes the peripheral’s procedures to restore its pre-sleep state upon wake-up. This function is expected to be called twice.
- When
init_end
isfalse
, it is called at a very early stage after wake-up. It is primarily used for variable initialization, but no device re-initialization is performed here. The second time it is called, withtrue
, it re-initializes devices and restores the pre-sleep state. - In TWENET, this is handled during the
vAHI_OnWakeup_MW()
call. The call order is as follows. For details, refer totwenet_main.c
in TWENETmcu.- Call of the
WarmMain()
function (the first function called upon wake-up)vAHI_OnWakeup_MW(FALSE)
- The
on_wakeup(false)
of the mwf library object is called here
- The
ToCoNet_vInit_Warm_Pre()
cbAppWarmStart(FALSE)
(orinit_warm()
in mwx)
ToCoNet_vBoard_Init()
- Initialization of the wireless microcontroller hardware (clock, etc.)
vAHI_OnWakeup_MW(TRUE)
- The
on_wakeup(true)
of the mwf library object is called here
- The
ToCoNet_vInit_Warm()
cbAppWarmStart(TRUE)
(orsetup()
in mwx)
- TWENET initialization
- TWENET application loop
- Call of the
class sys_global_resource_handler<T>
A high-level class for managing initialization and destruction procedures when multiple instances of the same function are defined, such as I2C and PWM.
It is used when there are procedures that need to be performed only once upon initialization and procedures that need to be destroyed only after all instances have been used. (Even with these peripherals, this class may or may not be used depending on the implementation.)
The initialization and destruction procedures are performed based on a reference counter (passed from the constructor) that is updated whenever an object is created or destroyed.
sys_ev_handler
is an abstract class, but this class uses CRTP.
init()
When the reference counter becomes 1
(i.e., when initialization is needed), T::global_init()
is called.
- This member function must be explicitly called from the peripheral class constructor.
deinit()
When the reference counter becomes 0
, T::global_deinit()
is called.
- This member function must be explicitly called from the peripheral class destructor.
class sys_ev_manager
A collection class for managing peripheral class objects in a single place. However, it does not own the objects; it stores sys_ev_handler
class pointers in a fixed array, using the ID specified by the ID_SYSHAND
enumeration as an index.
Its main purpose is to perform on_sleep()
and on_wake()
procedures in a batch.
Since which peripheral class objects are created depends on the user’s program, calling if(the_pwm1) the_pwm1->on_sleep();
for every class object would be inefficient and link unnecessary code. Instead, it stores them as abstract objects of type sys_ev_handler
and calls their virtual
methods.
global_init_sysevmgr()
Creates the the_sys_ev_manager
instance.
global_deinit_sysevmgr()
Destroys the the_sys_ev_manager
instance.
reg_obj()
Registers a peripheral class object.
unreg_obj()
Deregisters a peripheral class object.
on_wakeup(bool init_2nd)
Executes on_wake()
for all registered objects.
void on_sleep()
Executes on_sleep()
for all registered objects.
Peripheral Class Definition Example
class timer_n_pwm :
public mwf::sys_ev_handler // Base class
, public mwf::sys_global_resource_handler<timer_n_pwm> // Base class (only if needed)
{
using global_hdr = mwf::sys_global_resource_handler<timer_n_pwm>;
// Define a shorthand because the name is long
static uint32_t _global_init_ct;
// Reference counter for sys_global_resource_handler
public:
static void global_init_pwm(uint8_t u8_pwm_id, ...) { ... }
static void global_deinit_pwm_manager(uint8_t u8_pwm_id) { ... }
// Procedures for creating and destroying the actual instance of the_pwm?.
public:
// Constructor
timer_n_pwm(/* Constructor arguments */)
: mwf::sys_ev_handler(/*ID*/ ,static_cast<sys_ev_handler*>(this))
, mwf::sys_global_resource_handler<timer_n_pwm>(_global_init_ct)
{
global_hdr::init(); // Procedure for creating sys_global_resource_handler<>
}
// Destructor (defined as virtual because it inherits from an abstract class)
virtual ~timer_n_pwm()
{
global_hdr::deinit(); // Procedure for destroying sys_global_resource_handler<>
}
// Implementation of the sys_ev_handler class
virtual void on_sleep() { ... } // Called before sleep
virtual void on_wakeup() { ... } // Called after waking up from sleep
// Implementation of sys_global_resource_handler<>. Static member function.
static void global_init(); // The very first initialization procedure
static void global_deinit(); // The very last destruction procedure
};
...
uint32_t mwf::periph::timer_n_pwm::_global_init_ct; // The actual reference counter
The above is an excerpt from the definition of the PWM (mwf_periph_pwm.hpp
) peripheral class. Most other classes do not use sys_global_resource_handler<>
.
4.2.2 - mwf_periph_common - Peripheral common
mwf_periph_common - Peripheral common
include
#include "mwf_periph_common.hpp"
GPIO Operation Functions
These are static (inline) functions defined within struct pin
that you can call.
set_pin_as_input()
static void set_pin_as_input(uint8_t pin, uint32_t param = 0)
Sets pin
to an input state.
param
is unused.
set_pin_as_output()
static void set_pin_as_output(uint8_t pin, uint32_t param = PORTOUT_INITSTATE_HIGH)
Sets pin
to an output state.
- If
PORTOUT_INITSTATE_HIGH
is specified forparam
, the pin will be set to a HIGH state when this function is called.
set_output()
void set_output(uint8_t pin, uint8_t value)
Changes the output state of pin
. If value
is PORT_HIGH
(1), it sets the pin to HIGH; if PORT_LOW
(0), it sets it to LOW.
get_input()
static uint8_t get_input(uint8_t pin)
Reads the state of pin
when it is in an input state. The return value is PORT_HIGH
(1) for HIGH and PORT_LOW
(0) for LOW.
get_input_bm()
static uint32_t get_input_bm(uint32_t u32mask = 0x3FFFFF)
// Example
uint32_t bm = get_input_bm((1ul << 0) | (1ul << 3));
if (bm & (1ul << 3)) { ... } // If PIO3 is HIGH
else { ... } // If PIO3 is LOW
Reads the input state of all pins as a bitmap.
- The value of PIOn corresponds to the bit
(1UL << n)
. - The values of pins not in an input state are undefined.
In the example, you specify a pin bitmap (u32mask
) to get the state of input pins at once. For example, if you need the values for PIO0 and PIO3, you would specify (1ul << 0) | (1ul << 3)
.
The return value is also a bitmap of the input states. A HIGH level is represented by 1
, and a LOW level by 0
. For example, if PIO3 is HIGH, the 4th bit from the LSB will be 1
.
set_output_bm()
static void set_output_bm(uint32_t u32mask, uint8_t value)
// Example
set_output_bm((1ul << 0) | (1ul << 3), 0); // Sets PIO0 and 3 to LOW
Changes the output state for the pins corresponding to the bitmap specified by u32mask
.
- The value of PIOn corresponds to the bit
(1UL << n)
. - If
value
isPORT_HIGH
(1), it sets the output to HIGH; ifPORT_LOW
(0), it sets it to LOW.
In the example, you specify a pin bitmap (u32mask
) to set the output state of multiple pins at once. For example, to set PIO0 and PIO3, you would specify (1ul << 0) | (1ul << 3)
. The value
is 1
for a HIGH level and 0
for a LOW level.
PIN Operation Functions
These are static (inline) functions defined within struct pin
that you can call.
static void __conf_digital()
static void __conf_digital(uint8_t pin, uint8_t func)
This function sets IOCON_PIO_FUNC(func)
for the PIO register of the specified pin pin
.
IOCON->PIO[0][pin] =
( 0
| IOCON_PIO_FUNC(func) // SETFUNC (e.g. PWM is 0x04)
| IOCON_PIO_MODE(0x00u) // 0x00:pullup
| IOCON_PIO_DIGIMODE(0x01u)
| IOCON_PIO_INPFILT_OFF
);
static void conf_default()
static void conf_default(uint8_t pin)
This function reverts the pin to its default definition, as set in board/pin_mux.c
within the TWENETmcu library.
static void __conf_gpio_input()
static void __conf_gpio_input(uint8_t pin)
This is for internal use. It sets pin pin
as a GPIO input.
The user program should use set_pin_as_input()
.
static void __conf_gpio_output()
static void __conf_gpio_output(uint8_t pin, bool b_init_high = true)
This is for internal use. It sets pin pin
as a GPIO output. If b_init_high
is true
, the initial output is a HIGH (Vcc) level; if false
, it’s a LOW (GND) level.
The user program should use set_pin_as_output()
.
static void set_pullup()
static void set_pullup(uint8_t pin, uint8_t mode)
This function sets IOCON_PIO_MODE(mode)
for the PIO register of the specified pin pin
. This bit controls the pull-up behavior.
static void conf_pwmout()
static void conf_pwmout(uint8_t pin, bool b_enable)
This function uses __conf_digital()
to set IOCON_PIO_FUNC(0x04)
for the PIO register of the specified pin pin
. This typically configures the pin for PWM output.
static void conf_adc_input()
static void conf_adc_input(uint8_t pin)
For pins PIO14..19, this function makes the following settings to configure them for ADC:
IOCON->PIO[0][pin] =
( 0
| IOCON_PIO_FUNC(0x00u) // FUNC_ALT0
| IOCON_PIO_MODE(0x00u) // 0x00:pullup
| IOCON_PIO_DIGIMODE(0x00u) // ANALOGUE
| IOCON_PIO_INPFILT_OFF
);
static void conf_sclN_pioM()
static void conf_scl0_pio10() {
__conf_digital(10, 0x05);
}
static void conf_sda0_pio11() {
__conf_digital(11, 0x05);
}
static void conf_scl0_pio15() {
__conf_digital(15, 0x05);
}
static void conf_sda0_pio16() {
__conf_digital(11, 0x05);
}
static void conf_scl1_pio06() {
__conf_digital(06, 0x05);
}
static void conf_sda1_pio07() {
__conf_digital(07, 0x05);
}
static void conf_scl1_pio12() {
__conf_digital(12, 0x05);
}
static void conf_sda1_pio13() {
__conf_digital(13, 0x05);
}
These are configuration functions for using the pins for I2C.
static void conf_uart1(uint8_t tx, uint8_t rx)
static void conf_uart1(uint8_t tx, uint8_t rx)
This function specifies the TXD pin of UART1 as tx
and the RXD pin as rx
.
- You cannot set only one of the TXD or RXD pins with this function.
Others
struct ts_retention_context
struct ts_retention_context {
uint32_t u32_bm_io;
uint32_t u32_bm_set;
void save();
void restore();
};
static ts_retention_context s_retention_context;
static void retention_on_sleep()
static void retention_on_wake()
This is for internal use. It manages the processes and necessary data for retaining the GPIO output state during sleep.
static bool __b_check_swdbg_port(uint8_t pin)
static bool __b_check_swdbg_port(uint8_t pin)
This is for internal use. It determines whether a pin
is used by the debugger during a debug session.
Behavior during Sleep
- For pins whose GPIO output state has been set using
set_pin_as_output()
, the output state is maintained even during sleep. However,retention_on_sleep()
andretention_on_wake()
must be called appropriately. In TWENET, these functions are called during the pre-sleep and wake-from-sleep processes handled within the TWENETmcu and TWENETcmpt libraries.
4.2.3 - mwf_periph_adc - ADC
mwf_periph_adc - ADC
This is a peripheral object that summarizes the procedures for using the Analog-to-Digital Converter (ADC).
Code Example
The following example explicitly specifies the mwf::
namespace. To omit this, please write using namespace mwf;
.
- include
#include "mwf_periph_adc.hpp"
- Initialization Procedure
// Create the the_adc class object
mwf::the_adc->global_init_adc_manager();
// Specify ADC input pins
mwf::pin::conf_adc_input(14);
mwf::pin::conf_adc_input(15);
// Initialization
mwf::the_adc->init();
- ADC Start (One-shot)
// Specify channels
mwf::the_adc->enable(
(1ul << mwf::adc::CH_0)
| (1ul << mwf::adc::CH_1)
| (1ul << mwf::adc::CH_VCC));
// Start ADC
mwf::the_adc->start(); // One-shot
while(!mwf::the_adc->available()) {} // Wait for completion by polling
// Get values
int16_t v_ch0 = mwf::the_adc->get_value_mv(mwf::adc::CH_0);
int16_t v_ch1 = mwf::the_adc->get_value_mv(mwf::adc::CH_1);
int16_t v_vcc = mwf::the_adc->get_value_mv(mwf::adc::CH_VCC);
- ADC Start (Continuous)
// Specify channels
mwf::the_adc->enable(
(1ul << mwf::adc::CH_0)
| (1ul << mwf::adc::CH_1)
| (1ul << mwf::adc::CH_VCC));
// Start ADC
mwf::the_adc->start(true); // Continuous
// Inside the application loop.
void loop() {
if (mwf::the_adc->available()) {
// Get values (to be executed periodically)
int16_t v_ch0 = mwf::the_adc->get_value_mv(mwf::adc::CH_0);
int16_t v_ch1 = mwf::the_adc->get_value_mv(mwf::adc::CH_1);
int16_t v_vcc = mwf::the_adc->get_value_mv(mwf::adc::CH_VCC);
...
}
}
- Temperature Measurement
int32_t i32temp;
int16_t i16volt;
// Executes the process of turning on the internal sensor, waiting for stabilization, and performing ADC measurement (one time only).
mwf::the_adc->temp_capture(i32temp, i16volt, 0);
// i32temp is the temperature in degrees Celsius multiplied by 128. i16volt is in millivolts.
Serial << format("%dC %dmV", i32temp >> 7, i16volt);
class mwf::periph::adc
This section describes the main definitions for the the_adc
class object.
Constant Definitions
static const uint8_t CH_MAX = 7;
static const uint8_t CH_0 = 0; // ADC0
static const uint8_t CH_1 = 1; // ADC1
static const uint8_t CH_2 = 2; // ADC2
static const uint8_t CH_3 = 3; // ADC3
static const uint8_t CH_4 = 4; // ADC4
static const uint8_t CH_5 = 5; // ADC5
static const uint8_t CH_VCC = 6; // VCC
static const uint8_t CH_TEMP = 7; // Internal temperature sensor (the acquisition method differs from normal ADCs)
These are the configuration definitions for the ADC channels.
struct config
struct config {
uint8_t prescale;
};
This is a structure for setting configurations. It is passed as a parameter to init()
.
prescale
: (Current version only supportsDEFAULT_PRESCALE=6
) A prescale value that determines the ADC conversion time. It sets(1ul << .prescale)
toadc_config_t::clockDividerNumber
defined in the fsl library and calls::ADC_Init()
.
global_init_adc_manager()
global_deinit_adc_manager()
static void global_init_adc_manager();
static void global_deinit_adc_manager();
These functions create and destroy the the_adc
class object.
set_pin_as_adc()
static void set_pin_as_adc(uint8_t pin)
This function sets the specified pin number pin
as an ADC input.
init()
deinit()
void init(bool b_wait_init = true);
void deinit();
Initializes the ADC.
Setting b_wait_init
to FALSE
omits the ADC stabilization wait time (300ms). For details on handling the wait time, please refer to is_periph_enabled()
.
To initialize or re-initialize the ADC for internal temperature sensor acquisition, call init_for_temp_volt()
.
is_periph_enabled()
force_periph_enabled()
get_init_freerun_tick()
bool is_periph_enabled()
void force_periph_enabled()
uint32_t get_init_freerun_tick()
is_periph_enabled()
returns true
when the ADC has been initialized and the necessary waiting period has elapsed.
- If the FRWT (Free Running Wake Timer) provided by
the_wtimer
is running,is_periph_enabled()
will returnfalse
until the appropriate time has passed. You can get the tick count value at the timeinit()
was called by callingget_init_freerun_tick()
. - If the FRWT is not running, the first call to
is_periph_enabled()
will incur a wait time of approximately 300 microseconds. To avoid this waiting process, you can callforce_periph_enabled()
immediately after callinginit()
. This forces the internal state to be treated as if the waiting period has already passed.
enable()
void enable(uint32_t chmask);
This function sets the ADC to an operational state. chmask
is a bitmask of the channels to be converted. For example, if you want to target ADC0, ADC1, and VCC, you would specify (1ul << CH_0) | (1ul << CH_1) | (1ul << CH_VCC)
.
start()
stop()
void start(bool b_cont = false);
void stop();
After calling enable()
, you can start the ADC by calling start()
. If b_cont
is set to true
, it will perform continuous conversion. Do not call start()
if the ADC is already running.
To stop the conversion during continuous mode, call stop()
.
When the conversion is complete, a read of the_adc->available()
will return true
.
available()
bool available();
Returns true
after the conversion is complete. After true
is read, it returns false
again.
is_started()
bool is_started();
Returns true
if the ADC is currently running due to a call to start()
.
get_value()
uint16_t get_value(uint8_t ch);
Gets the 12-bit AD converted value for the channel specified by ch
. Call this after the AD conversion is complete.
get_value_mv()
int16_t get_value_mv(uint8_t ch);
Gets the AD converted value in millivolts (mv) for the channel specified by ch
. Call this after the AD conversion is complete.
global_init_device()
global_deinit_device()
static void global_init_device();
static void global_deinit_device();
Performs the procedures for hardware initialization and termination of use.
Note: This is called internally from constructors, destructors, etc., and does not need to be explicitly called from the user application.
register_callback()
typedef void (*PFN_ADC_CALLBACK)(uint32_t, uint32_t);
void register_callback(PFN_ADC_CALLBACK pfn)
Specifies a callback function from within an interrupt handler.
The first parameter of the callback function is kADC_ConvSeqAInterruptFlag
, and the second parameter is a bitmask of the channels that were converted.
Temperature Sensor
temp_capture()
bool temp_capture(
int32_t& temp128th,
int16_t& volt_mv,
uint8_t times_adc_scaler = 0,
bool b_power_on_temp_sensor = true)
Acquires the value of the on-chip temperature sensor. It also secondarily measures the supply voltage.
temp128th
: Specifies the variable to store the temperature measurement result. The value is 128 times the value in degrees Celsius. The integer part can be calculated withtemp128th >> 7
, and the first decimal place with(10 * temp128th) >> 7
.volt_mv
: Specifies the variable to store the voltage measurement result. The value is in millivolts [mV].times_adc_scaler
: Specifies a scaler value corresponding to the number of ADC repetitions. A value from 0 to 3 can be specified; 0 performs 1 AD conversion, 1 performs 2, 2 performs 4, and 3 performs 8, after which the values are averaged.- The return value is
true
on success andfalse
on failure.
The following processes are performed implicitly:
- If the temperature sensor is not ON, it is set to ON and the necessary waiting process is performed (see
temp_power_on()
). - The temperature sensor is turned OFF after execution.
- It will fail if the ADC has not been initialized (
init()
). - If the device is not available after ADC initialization, it performs a waiting process (see
is_periph_enabled()
).
temp_get_capt_tick()
uint32_t temp_get_capt_tick()
This function returns the FRWT counter value from the last time the temperature was acquired.
temp_power_on()
, temp_power_off()
void temp_power_on()
void temp_power_off()
These functions explicitly turn the temperature sensor ON/OFF.
If FRWT is enabled, you can shorten the waiting time by calling temp_power_on()
in advance, as the function determines if the wait is complete based on the counter value.
temp_computation()
int32_t temp_computation(
uint16_t adcout_vbat_lsb_sum8,
uint16_t tsens_adcout_T_sum8,
uint8_t nb_samples_actual = 1)
This is for internal use. It calculates the temperature from the ADC measurement values.
get_ctrl0_adc_reg_context()
class ctrl0_adc_reg;
ctrl0_adc_reg get_ctrl0_adc_reg_context(uint8_t mode, uint8_t tsamp)
// Example
if (auto rc = get_ctrl0_adc_reg_context(
0x0
, 0x14
)) {
; // This scope enables the (0x0, 0x14) setting. The original value is restored upon exiting the scope.
}
This is for internal use. It temporarily changes the ADC configuration parameters.
class mwf::periph::adc
(sys_ev_handler
)
on_sleep()
Performs the ADC stop process.
on_wakeup()
If the ADC was initialized before sleep, it performs the initialization procedure (init()
). You must execute enable()
and start()
again.
Others
About Operation in Continuous Mode
The conversion cycle is determined by the hardware. In the current version, the prescaler value is fixed.
Usage with AHI and mwx
The mwf::the_adc
is used internally by the AHI and mwx libraries, so caution is required when using it directly.
- If you are using the AHI library and also
mwf::the_adc
, please avoid calling any ADC-related procedures directly (e.g.,vAHI_ApConfigure()
,vAHI_AdcEnable()
,vAHI_AdcStartSample()
inadc.c
that comes with App_Tweline). - If you are using the mwx library and also
mwf::the_adc
, please do not perform operations on theAnalogue
class object (e.g.,Analogue.setup()
).
4.2.4 - mwf_periph_gint - GINT(GPIO)
mwf_periph_gint
- GINT(GPIO)
Implements general-purpose I/O input/output settings and I/O interrupts using GINT.
In TWENET, initialization and interrupt handling are processed within the TWENET library (TWENETcmpt). User programs typically do not need to call these functions directly.
include
#include "mwf_periph_gint.hpp"
class mwf::periph::gint
This is the definition for the the_gint
class object. The creation of a the_gint
class object is required to use pins for interrupt operations (including sleep interrupts). For implementation details, please refer to the “GINT-based DIO Interrupt Implementation” section below.
global_init_gint_manager()
global_deinit_gint_manager()
static void global_init_gint_manager();
static void global_deinit_gint_manager();
These functions create and destroy the the_gint
class object.
init_int()
deinit_int()
void init_int(tpf_gpio_int_handler pf_callback, void *p_data = nullptr);
void deinit_int();
Initializes the GPIO interrupt. You can specify the interrupt handler (pf_callback
) and a parameter (p_data
) to be passed to the interrupt handler.
To stop the GPIO interrupt, call deinit_int()
.
pf_callback
is defined as follows:
using tpf_gpio_int_handler = void(*)(uint32_t bm_now, uint32_t bm_changed, void *p_data);
bm_now
: A bitmap corresponding to the current pin states.bm_changed
: A bitmap corresponding to the pins that have changed.p_data
: Thep_data
specified ininit_int()
.
set_int_pins_bm()
void set_int_pins_bm(uint32_t u32mask_rising_edge, uint32_t u32mask_falling_edge);
This function specifies the pins to be targeted for interrupts.
The first parameter, u32mask_rising_edge
, is a bitmap of the pins for which to detect a rising edge. The second parameter, u32mask_falling_edge
, is a bitmap of the pins for which to detect a falling edge.
It is also possible to set both rising and falling edges.
gint_poll()
void gint_poll();
Performs the same process as the interrupt handler.
Calling this function periodically from a 1ms system timer, for example, can sometimes alleviate the limitations described in the “GINT-based DIO Interrupt Implementation” section below (where a port state might change after being read in the interrupt handler and that change is not processed). In most cases, this process is not necessary.
set|unset|get_opt_stop_int_when_changed()
void set_opt_stop_int_when_changed();
void unset_opt_stop_int_when_changed();
bool get_opt_stop_int_when_changed();
These functions stop the interrupt operation for a pin after a state change is detected, which helps mitigate the effects of mechanical button bouncing, etc.
Specifically, when a pin’s state changes and an interrupt occurs, the pin that was determined to have changed within the interrupt handler is temporarily excluded from being an interrupt pin.
*Since the GINT interrupt mechanism cannot determine which pin caused the interrupt, the state of the pins is read immediately after the interrupt handler executes and compared with the previous state to detect a change.
If this option is set, you should call reactivate_in_pins()
after a pin change has been detected and the pin state has stabilized.
reavtivate_int_pins()
void reavtivate_int_pins();
This function resumes interrupts for pins that were temporarily stopped. Refer to the set_opt_stop_int_when_changed()
option setting for details.
get_gint_context()
gint_context& get_gint_context();
This function accesses the internal structure. It is used to get the bitmaps of the configured rising and falling edge pins (.bm_rise
and .bm_fall
) and the wake-up cause pin during sleep (.bm_wake
).
_gint_update()
std::tuple<uint32_t, uint32_t> _gint_update(
uint32_t u32mask_rising_edge = 0x80000000
, uint32_t u32mask_falling_edge = 0x80000000);
(Internal function, not to be used from user programs)
- Configures the interrupt pins.
- Determines and updates the pin state changes (if
u32mask_rising_edge
andu32mask_falling_edge
are0x80000000
). If a state change occurs, it calls the callback function registered withinit_int()
.
gint_handler()
static void gint_handler();
(This is an internal function and should not be used from user programs)
The GINT interrupt handler.
_gint_get_changed_by_specified_edge()
uint32_t _gint_get_changed_by_specified_edge(uint32_t bm_cur, uint32_t bm_changed)
(This is an internal function and should not be used from user programs)
This function extracts the pins that match the specified rising or falling edge conditions from the changed pins. The calculation uses the current bitmap state (bm_cur
) and the changed pins (bm_changed
).
class mwf::periph::gpio
(sys_ev_handler
)
on_sleep()
Stops the interrupt if GINT is active.
In TWENET, vAHI_DioOnSleep_MW()
sets the interrupt-configured pins (configured via this library using set_int_pins_bm()
) for wake-up from sleep. Note that you cannot specify rising or falling edges for wake-up from sleep.
on_wakeup()
If woken up by a GPIO interrupt, this function saves the pin information corresponding to the wake-up cause (PMC->WAKEIOSOUCE
).
Also, if interrupt pins were specified before sleep, it re-initializes GINT so that the interrupt operation resumes.
GINT-based DIO Interrupt Implementation
Because the PINT functionality is limited to a maximum of 4 ports, a similar function has been implemented using GINT (Group INT). Since GINT is not an interrupt detection mechanism focused on specific pins like PINT, there are some limitations. As the TWENET library does not use PINT, if the limitations of the GINT implementation are problematic, you should consider implementing a PINT-based solution.
Limitations
- Signals that change state again shortly after a state change, such as noise or short pulses, may lead to unexpected behavior (e.g., missed detections).
- It is assumed that the same state will be maintained for a certain period after a state change.
- Due to GINT’s constraints, a very short pulse can be detected by the GINT interrupt, but it is not possible to determine which pin has changed. For details, please refer to the “Implementation” section below.
- If a state is maintained for about 10µs after an edge, the GINT edge can be re-configured, so it is expected to work in principle. However, for safety, a duration of about 30-50µs (equivalent to one interrupt handler execution time) is recommended as a guideline for the state to remain the same.
- When detecting a falling edge from a GND state, and conversely, when detecting a rising edge from a VCC state, missed detections are more likely to occur in principle.
- For signals containing chattering or noise, use the option to temporarily disable interrupts for the pin upon the first interrupt occurrence (
vAHI_DioInterruptDisablePinsIntWhenChanged_MW(TRUE);
ormwf::the_gpio->set_opt_stop_int_when_changed();
). After waiting for a certain period for the pin state to stabilize, callvAHI_DioInterruptReavtivate_MW();
ormwf::the_gpio->reavtivate_int_pins();
. - Although not necessary in most cases, calling
the_gpio->gint_poll()
periodically (e.g., from a 1ms system tick) can increase interrupt overhead but may mitigate the effect of missed detections.
- It is assumed that the same state will be maintained for a certain period after a state change.
Note: The values mentioned are based on a CPU operating at 32MHz.
Note: If you wish to use the semiconductor’s functions directly, please do so without initializing this library and use GINT or PINT directly.
Implementation
GINT’s original purpose is to treat multiple pins as a group and generate an interrupt when there is a change in the group as a whole, not to be aware of the state of individual pins.
It is implemented as follows:
- The current pin state is read, and the GINT detection edge is set (falling for HIGH, rising for LOW) to enable the interrupt.
- A GINT interrupt occurs (a change on one of the pins triggers the interrupt handler).
- The state of each pin is read to detect which pins have changed.
- The GINT detection edge setting is reconfigured to match the newly read pin states.
- The application is notified (via a callback) of the pins that have changed.
Note: The interrupt handler will be called again immediately afterward.
Note: The values and numbers shown are based on a library code under development, with two target pins for detection and a microcontroller operating at 32MHz.
When two pins go to a LOW level at the same time
The interrupt handler is called 1.5µs after the interrupt occurs. The pre-interrupt processing (reading pins and reconfiguring the detection edge) takes up to 6.6µs. After that, the application is notified (via the interrupt callback), which takes until 22µs after the interrupt occurred.
The interrupt occurs one more time (this is thought to be the behavior of the GINT hardware). In the second interrupt, no state change is usually detected, but it may suppress exceptional missed detections.

- Horizontal axis: (10µs/DIV)
- Pink: From the start of the interrupt handler until the GINT detection edge is reconfigured (1V/div)
- Cyan/Yellow: Input signal (2V/div)
If another pin changes during the interrupt handler, example 1
In this example, another pin (cyan) changed during the first part of the interrupt handler, so it was processed consistently within the first handler. The behavior is the same as the simultaneous change mentioned above. The changes of both the yellow and cyan pins are communicated to the application in the first interrupt.

- Horizontal axis: (10µs/DIV)
- Pink: From the start of the interrupt handler until the GINT detection edge is reconfigured (2V/div)
- Blue: From the start to the end of the interrupt handler (2V/div)
- Cyan/Yellow: Input signal (5V/div)
If another pin changes during the interrupt handler, example 2
In this example, another pin (cyan) changes during the interrupt handler, but since the change occurs after the detection edge has been reconfigured, an interrupt occurs immediately afterward. A third handler is executed after the second handler finishes. The change of the yellow pin is communicated to the application in the first interrupt, and the change of the cyan pin is communicated in the second interrupt.

- Horizontal axis: (10µs/DIV)
- Pink: From the start of the interrupt handler until the GINT detection edge is reconfigured (2V/div)
- Blue: From the start to the end of the interrupt handler (2V/div)
- Cyan/Yellow: Input signal (5V/div)
4.2.5 - mwf_periph_i2c - I2C
mwf_periph_i2c
- I2C
This is a peripheral object that summarizes the procedures for using the I2C bus.
Code Example
The example below explicitly specifies the mwf::
namespace. If you want to omit it, write using namespace mwf;
.
- Include
#include "mwf_periph_i2c.hpp"
- Initialization
// create instance of the_i2c0.
if (!mwf::the_i2c0) {
mwf::i2c::global_init_i2c0_manager();
}
// I2C device init
mwf::the_i2c0->init();
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write_blocking(0x70, cmd1)) return false;
// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.
// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read_blocking(0x70, data);
- Read (Blocking API)
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write_blocking(0x70, cmd1)) return false;
// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.
// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read_blocking(0x70, data);
In this example, a command to start data acquisition is sent to the sensor, and after waiting for the sensor’s operation time (the time required by the sensor), data acquisition is performed.
- Reading (Non-blocking API)
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write(0x70, cmd1)) return false;
while(!mwf::the_i2c0->available()); // waiting for completion of write operation.
// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.
// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read(0x70, data);
while(!mwf::the_i2c0->available()); // waiting for completion of read operation.
These are the same write()
and read()
functions as the blocking API, but with the non-blocking API, they return immediately without waiting for the data transmission to complete. You must either wait a sufficient amount of time or wait for the_i2c0->available()
to become true
before performing subsequent operations (in the example above, polling is performed immediately after write()
/read()
, so there is no difference in usage from the blocking API).
class mwf::periph::i2c
Describes the procedures for using I2C.
*Note: In the current implementation, only the the_i2c0
class object, which uses I2C0, is available.
E_PIN_CONF
enum class E_PIN_CONF : uint8_t {
NODEF = 0, // Not specified
PRIMARY = 1, // Primary assignment (PIO10/11)
ALT = 2 // Alternate assignment (PIO15/16)
};
// Type for assignments, comparisons, etc. between enum class and int types.
using wE_PIN_CONF = mwf::enum_wapper<E_PIN_CONF>;
This is an enumeration for specifying pin assignments.
global_init_i2c0_manager()
, global_deinit_i2c0_manager()
static void global_init_i2c0_manager(wE_PIN_CONF pin_conf = E_PIN_CONF::PRIMARY);
static void global_deinit_i2c0_manager();
These functions create and destroy the the_i2c0
class object.
During creation, you can specify the pin configuration with pin_conf
as either E_PIN_CONF::PRIMARY
(value 0, SCL=PIO10, SDA=PIO11) or E_PIN_CONF::ALT
(value 1, SCL=PIO15, SDA=PIO16). The pin initialization is performed when init()
is called.
(eE_PIN_CONF
is a wrapper class for enum class E_PIN_CONF
, with definitions for assignment and comparison with int
types.)
init()
, deinit()
void init(uint32_t clock_freq = 0, wE_PIN_CONF pin_conf = E_PIN_CONF::NODEF);
void deinit();
Initializes the I2C bus and performs the termination procedure. During initialization, clock_freq
is provided as a parameter; if it is 0
, the default clock of 100kHz is selected; otherwise, clock_freq
[Hz] is specified as the frequency.
If pin_conf
is not specified (E_PIN_CONF::NODEF
value 0), the pins specified in global_init_i2c0_manager()
are used. If pin_conf
is specified, the pins are initialized with that setting. Thereafter, if this parameter is omitted, the last specified pins will be used.
write_blocking()
, write()
bool write_blocking(uint8_t addr, const uint8_t* buf, unsigned size);
template <unsigned N> bool write_blocking(uint8_t addr, const uint8_t (&buf)[N]);
bool write(uint8_t addr, const uint8_t* buf, unsigned size);
template <unsigned N> bool write(uint8_t addr, const uint8_t (&buf)[N]);
These functions write data to the I2C bus.
write_blocking()
is a blocking function that waits for the write to complete. write()
is a non-blocking function that returns immediately without waiting for the write to finish. When the write is complete, .available()
will be true
.
addr
is the 7-bit I2C bus address, buf
is the data to be written, and size
is the number of bytes to write. If buf
is a fixed-size array of size N
, N
bytes are written.
read_blocking()
, read()
bool read_blocking(uint8_t addr, uint8_t* buf, unsigned size);
template <unsigned N> bool read_blocking(uint8_t addr, uint8_t(&buf)[N]);
bool read(uint8_t addr, uint8_t* buf, unsigned size);
template <unsigned N> bool read(uint8_t addr, uint8_t(&buf)[N]);
These functions read data from the I2C bus.
read_blocking()
is a blocking function that waits for the read to complete. read()
is a non-blocking function that returns immediately without waiting for the read to finish. When the read is complete, .available()
will be true
.
addr
is the 7-bit I2C bus address, buf
is the data storage buffer, and size
is the number of bytes to read. If buf
is a fixed-size array of size N
, N
bytes are read.
_transfer()
bool _transfer(OPT op, uint8_t addr, uint8_t* buf, unsigned size);
This function performs non-blocking read/write operations. op
specifies whether to read or write, addr
is the I2C bus address, buf
is the buffer for reading or writing, and size
is the number of bytes to read or write.
_transfer_blocking()
, _start_blockin()
, _stop_blocking()
bool _transfer_blocking(OPT op, uint8_t* buf, unsigned size, bool sendStop = false)
bool _start_blocking(OPT op, uint8_t addr);
bool _stop_blocking();
These functions are adjusted for the mwx library to perform blocking read/write procedures. Call _start_blocking()
, _transfer_blocking()
as many times as needed, and then _stop_blocking()
. The sendStop
parameter in _transfer_blocking()
can be set to true
on the last transfer to appropriately send a STOP signal.
available()
bool available();
This function determines if a transfer has finished when using the non-blocking API. It returns true
when the transfer is complete.
is_success()
bool is_success();
When using the non-blocking API, this function returns whether the last transfer was successful. A return value of true
indicates that the transfer was successful.
class mwf::periph::i2c
(sys_ev_handler
)
on_sleep()
As a procedure before sleep, it terminates the use of the I2C device.
on_wakeup()
If the device was initialized (init()
call) before sleep, init()
is called again to re-initialize it.
4.2.6 - mwf_periph_ntag - NTAG
This page only describes the EEPROM procedures.
Information on how to handle NTAG communication will be added at a later date.
mwf_periph_ntag
- NTAG
This describes the procedures for reading and writing to the EEPROM of the short-range wireless communication (NTAG) controller (NT3H2211) built into the chip. The controller is connected via I2C, but it does not use mwf::periph::i2c
.
This procedure allows reading and writing to a 1KB area (NT3H2211 I2C block addresses 64-127).
Code Example
#include "mwf_periph_ntag.hpp"
void func() {
// create the_ntag class object.
if (!mwf::the_ntag) {
mwf::ntag::global_init_ntag_manager();
}
// initialize
mwf::the_ntag->init();
// write 128bytes
uint8_t xfer1[128];
for (unsigned i = 0; i < 128; i++) xfer1[i] = i;
mwf::the_ntag->write_user_area(0x00, xfer1);
// read 128bytes
uint8_t xfer2[128];
mwf::the_ntag->read_user_area(0x00, xfer2);
}
class mwf::periph::ntag
global_init_ntag_manager()
, global_deinit_ntag_manager()
static void global_init_ntag_manager();
static void global_deinit_ntag_manager();
These functions create and destroy the the_ntag
class object.
init()
, deinit()
void init();
void deinit();
These functions perform initialization and termination procedures for device access. Initialization (init()
) includes a waiting period of 300µs.
write_user_area()
bool write_user_area(uint16_t addr, const uint8_t *p, uint16_t len);
template <unsigned N> bool write_user_area(uint8_t addr, const uint8_t (&buf)[N]);
This function writes a byte sequence to the EEPROM user area.
addr
specifies the starting address from 0 to 1023. p
or buf
is the buffer for the data to be written. len
or N
is the number of data bytes.
read_user_area()
bool read_user_area(uint16_t addr, uint8_t *p, uint16_t len);
template <unsigned N> bool read_user_area(uint8_t addr, const uint8_t (&buf)[N]);
This function reads a byte sequence from the EEPROM user area.
addr
specifies the starting address from 0 to 1023. p
or buf
is the destination buffer for the data to be read. len
or N
is the number of data bytes.
class mwf::periph::ntag
(sys_ev_handler
)
on_sleep()
Performs the termination procedure before sleep.
on_wakeup()
If the device was initialized before sleep, it re-initializes it. If re-initialization is not required, call deinit()
before sleeping.
4.2.7 - mwf_periph_pwm - PWM, Timer
mwf_periph_pwm
- PWM, Timer
This is a peripheral object that summarizes the procedures for using PWM and timers.
The the_pwm[]
class object is used for operations. Although the class object is defined as an array, you can use PWM0 (the_pwm[0]
) to PWM9 (the_pwm[9]
).
PWM10 is not supported by this library.
Code Example
The example below explicitly specifies the mwf::
namespace. If you want to omit it, write using namespace mwf;
.
#include "mwf_periph_pwm.hpp"
// in some func.
void func() {
// create instance of PMW0.
if (!the_pwm[0]) { // The class object of PMW0 is the_pwm[0].
timer_n_pwm::global_init_pwm_manager(
0, // PWM0
timer_n_pwm::PIN::ALT,
// The timer_n_pwm::PIN::PRIMARY will assign smaller PIO number PIO0 from PWM0,
// or conversely, timer_n_pwm::PIN::::ALT assigns PIO12.
true // set true to enable PWM output.
);
}
// set `x' as an alias of the_pwm[0].
auto& x = the_pwm[0];
// Init the device
//x->init(); // not necessary, the constructor will call init() implicitly.
// if needs INT, set true. (default: false)
x->set_int_enabled(true);
// set prescale
x->set_prescale(6); // 0:32MHz 1:16Mhz 2:8Mhz ...
// set polarity: if false, set HIGH while active state. (default: false)
x->set_invert(false);
// set cycle
// note: 500Hz Duty 10% (Hi 0.2ms, Low 1.8ms)
x->set_cycle(
100 // conut for an active state (HIGH)
, 999 // count for a period (+1)
);
// start PWM out
x->restart();
}
// INT handler (call set_int_enabled() before restart())
// note: if TWENETcmpt library is not linked, the IRQ handlers for PWM1..9 shall be defined.
extern "C" void PWM0_IRQHandler(void) {
... // some procedures.
PWM_ClearStatusFlags(PWM, kPWM_Pwm0);
}
class mwf::periph::timer_n_pwm
global_init_pwm_manager()
static void global_init_pwm_manager(
uint8_t u8_pwm_id
, uint8_t u8_pin_number
, bool b_output_enabled = true
);
static void global_init_pwm_manager(
uint8_t u8_pwm_id
, PIN e_pin
, bool b_output_enabled = true
);
To construct the the_pwm[]
class object, you specify the PWM number and the corresponding pin.
The PWM number is specified as u8_pwm_id
. Each PWM has two available pins (PWM5 only has PIO16). In this API, you can either specify the pin number directly as u8_pin_number
or specify the lower pin number (timer_n_pwm::PIN::PRIMARY
) or the other pin number (timer_n_pwm::PIN::ALT
) from the available pins.
The behavior is undefined if you specify a conflicting number.
global_deinit_pwm_manager()
static void global_deinit_pwm_manager(uint8_t u8_pwm_id);
This function destroys the constructed the_pwm[]
class object.
set_pwm_output()
void set_pwm_output(bool_t b_enable);
bool get_pwm_output();
Changes the output state of the pin. If b_enable
is true
, the output is enabled, and the hardware pin settings are also changed. If it is false
, the pin is set to the default setting (conf::pin::conf_default()
).
- This function can be called while PWM is active.
- If the output is already set by a parameter in
global_init_pwm_manager()
, there is no need to call this function again.
set_int_enabled()
void set_int_enabled(bool_t b_enable);
bool get_int_enabled();
This function sets the interrupt to be enabled or disabled. If b_enable
is true
, the interrupt is enabled; if it is false
, it is disabled.
- This function can be called while PWM is active.
- Please refer to the “Interrupt Handler” section below.
set_prescale()
, set_divisor()
void set_prescale(uint8_t u8_prescale);
void set_divisor(uint16_t u16_div);
These functions set the prescale for PWM control, which determines the PWM control frequency.
- These functions can be called while PWM is active.
- If
set_prescale(u8_prescale)
is specified, the control frequency is determined as follows:0
: 32MHz,1
: 16MHz,2
: 8MHz, …,9
: 62500Hz,10
: 31250Hz. Values11
and above are undefined (assert in debug mode). - If
set_divisor(u16_div)
is specified, the control frequency is (32MHz / u16_div). The valid range is 1 to 1024, and the behavior is undefined if a value outside this range is specified. - The PWM period and duty cycle are determined by the parameters of
set_cycle()
.- For example, if
set_prescale(2)
is specified, the control frequency is fb=8MHz. With this setting, ifset_cycle(2, 10)
is specified, the PWM period is fb/10 = 800kHz, and the pulse width is 2/fb = 2/8000000 = 250ns.
- For example, if
set_cycle()
void set_cycle(uint16_t ct_comp, uint16_t ct_period);
uint16_t get_period_val(); // get total period count
uint16_t get_comp_val(); // get active region count
This function specifies the count values that determine one PWM cycle and the active period within it. The pin value changes during the active period, and an interrupt is generated at its end.
ct_comp
is the count for the active period, and ct_period
is the total count for one cycle. For example, if ct_comp
is 100
and ct_period
is 1000
, the PWM period will be 1000 counts at the PWM control frequency. With set_invert(false)
, the behavior will be HIGH for 100 counts and LOW for the remaining 900 counts.
- This function can be called while PWM is active.
ct_comp
is valid from0
toct_period - 1
. The upper limit for the active period ratio is(ct_period - 1) / ct_period
, and it cannot be set to 100%.set_duty()
takes a 100% setting into consideration.- The count value for one cycle,
ct_period
, is set asct_period - 1
in the hardware register. Please be careful not to specify the hardware register value directly in this function.
set_duty()
void set_duty(uint16_t u16duty, uint16_t u16duty_max = 1000);
This function sets the PWM duty cycle.
- You must have previously used
set_cycle()
to specify the count for one PWM cycle. If you omit this step,u16duty_max
is set as the PWM cycle count. - The active period is set to a ratio of
u16_duty/u16duty_max
of the total cycle. For example, ifset_duty(100)
is specified, the active period is 10% of the cycle. - If
u16duty
is set to the same value asu16duty_max
, the entire cycle becomes active, resulting in a HIGH level if the default non-inverted waveform output (set_invert(false)
) is used. (Due to hardware constraints, the active period cannot be set to the entire cycle. Internally, the waveform output register is inverted, and the active period is set to 0.)- For this reason, if you call
set_cycle()
after setting the duty cycle to 100% withset_duty()
, the waveform will be inverted. Please be careful not to mix their usage.
- For this reason, if you call
set_invert()
void set_invert(bool_t b_invert);
bool get_invert();
This function inverts the output waveform. When set to false
(default), the active period is at a HIGH level. When set to true
, it is at a LOW level.
start()
, stop()
void start();
void restart();
void stop();
These functions start, restart (with current settings), and stop the PWM output.
- When stopped with
stop()
, the pin state is LOW ifset_invert(false)
(default) is set, and HIGH ifset_invert(false)
is set.
class mwf::periph::timer_n_pwm
(sys_ev_handler
)
sys_ev_handler
is a procedure for before and after sleep.
on_sleep()
The PWM execution state is saved, and the pin state is returned to the default setting during sleep.
on_wakeup()
The state saved before sleep is restored.
class mwf::periph::timer_n_pwm
(sys_global_resource_handler
)
The sys_global_resource_handler<T>
(where T
is the timer_n_pwm
class) is a procedure for performing necessary initialization and termination only once for multiple PWM class objects. It is used implicitly internally.
- The constructor and
on_wakeup()
callsys_global_resource_handler<T>::init()
.- If it’s the first instance created, it calls
T::global_init()
.
- If it’s the first instance created, it calls
- The destructor and
on_sleep()
callsys_global_resource_handler<T>::deinit()
.- If it’s the last instance to be destroyed, it calls
T::global_deinit()
.
- If it’s the last instance to be destroyed, it calls
T::global_init()
Calls ::PWM_Init()
to initialize the PWM.
T::global_deinit()
Calls ::PWM_DeInit()
to terminate the use of the PWM.
Interrupts
When set_int_enabled(true)
is set, an interrupt is generated at the end of the active period. The interrupt handler is provided by the system and is named PWMn_IRWHandler()
(where n
is the PWM channel).
Interrupt
V Interrupt
V
Vcc +----+ +----+
| | | | t
GND----+ +----------------+ +-------------->
<----> Active Period
<--------------------> One PWM Cycle
The interrupt handler must be explicitly defined. The handler function that needs to be defined changes depending on whether the TWENETcmpt library is linked.
- If TWENETcmpt is linked, only define the handler for the PWM channel you are using.
- If TWENETcmpt is not linked, you must explicitly define interrupt handlers for all PWM channels from PWM0 to PWM9, even if you are not using an interrupt.
Interrupt Handler
When using TWENET, interrupts are converted into an interrupt function (cbToCoNet_u8HwInt()
) and an event (cbToCoNet_vHwEvent()
).
If you want to define your own interrupt handler, you must define PWNn_IRQHandler()
separately. The following example shows a definition for PWM1. When you define your own, TWENET interrupts and events will not be generated.
// note: in c file, `extern "C"' should be removed.
extern "C" void PWM1_IRQHandler(void) {
PWM_ClearStatusFlags(PWM, kPWM_Pwm1);
}
4.2.8 - mwf_periph_rng - TRNG
mwf_periph_rng
- TRNG
This implements the_rng
, a peripheral object that summarizes the procedures for using the chip’s built-in random number generation hardware.
With TWENET, this is used implicitly, so no initialization procedure is required in the user’s program.
Code example
if (!mwf::the_rng) {
mwf::rng::global_init_rng_manager();
mwf::the_rng->init();
}
uint32_t val = mwf::the_rng->random();
class mwf::periph::rng
global_init_rng_manager()
, global_deinit_rng_manager()
static void global_init_rng_manager();
static void global_deinit_rng_manager();
These functions create and destroy the the_rng
class object. The class object is automatically initialized upon creation, and random values can then be obtained.
random()
uint32_t random()
Returns a random value.
class mwf::periph::rng
(sys_ev_handler
)
on_sleep()
Performs the TRNG stop procedure.
on_wakeup()
Performs the TRNG startup procedure.
4.2.9 - mwf_periph_spi - SPI
mwf_periph_spi
- SPI
This implements the_spi1
, a class object for using the SPI bus.
- SPI0 support is not included in the code.
- Some definitions are included for non-blocking operations, but only blocking APIs are available in the current version.
Code Example
#include "mwf_periph_spi.hpp"
void func_spi_init() {
if (!mwf::the_spi1) {
mwf::spi::global_init_spi1_manager();
Serial << crlf << "the_spi1 constructed.";
}
mwf::spi::config conf{};
conf.baud = 4000000UL; // 4MHz
conf.bits = 8; // 8bit
conf.dir = mwf::spi::E_SPI_DIR::MSB_FIRST;
conf.mode = mwf::spi::E_SPI_MODE::MODE_3_INV_RISE;
conf.pin_ssel[0] = mwf::spi::E_PIN_SSEL::SSEL0_PIO3;
conf.pin_ssel[1] = mwf::spi::E_PIN_SSEL::SSEL1_PIO16;
mwf::the_spi1->init(conf);
}
void func_spi_transfer() {
uint8_t tx[16] = { 0xa5, 0x5a, 0x11, 0x88 }; // data to transmit
uint8_t rx[16]; // receive buffer
mwf::the_spi1->ssel_select(0);
mwf::the_spi1->transfer_blocking(tx, rx, 4); // four bytes transfer
CLOCK_uDelay(5); // wait 5us
mwf::the_spi1->transfer_blocking(tx, rx, 4); // four bytes transfer
mwf::the_spi1->ssel_deselect();
}
class mwf::periph::spi
struct config
The mwf::periph::spi::config
structure is defined as follows:
struct config {
// evaluated only in init()
E_PIN_MAIN pin_conf; // master pin configuration (so far not used)
E_PIN_SSEL pin_ssel[3]; // SSEL0..2 (assignment settings for slave select pins.
// At least pin_ssel[0] shall be configured.
// evaluated in conf(), reconf()
uint32_t baud; // SPI frequency (default 50Mhz)
E_SPI_DIR dir; // transfer LSB first
E_SPI_MODE mode; // SPI mode (clock polarity and detect edge)
uint8_t bits; // bit width (0:default=8, ...)
uint8_t ssel; // 0..3 or 0x80..0x80 (if MSB is set, assert/deassert SSEL automatically)
};
You set values in the structure and call init()
. The structure’s settings are copied internally during the init()
call, so you can discard the structure’s memory area afterward.
Here is an explanation of each member of the structure:
Signal Name | Description |
---|---|
pin_conf | Specifies the pin assignment (primary or alternate). If E_PIN_CONF::NODEF (=0) is selected, the setting from global_init_spi1_manager() is used. |
pin_ssel[3] | Specifies the SELECT pins. Index 0 of the array specifies the pin for SPI SELECT 0 (SSEL0), index 1 for SSEL1, and index 2 for SSEL2. SSEL0 must always be specified, while SSEL1 and SSEL2 should be set to E_PIN_SSEL::SSEL_VOID=0 . If you use two types of pins, specify SSEL0 and SSEL1; if you use three, store values in all of them.*Note: If you specify a software-controlled pin (e.g., E_PIN_SSEL::SSEL0_PIO3 ), all select pins will be software-controlled. With software control, the pins are set to a continuous HIGH level output and change to a LOW level when selected. TWENETcmpt (AHI library compatible) uses software control.*Note: With hardware control, the SELECT pin control follows the behavior of SPI_MasterTransferNonBlocking() in fsl_spi.c. |
baud | Specifies the SPI clock frequency. It can be set up to 32MHz, but frequencies around 1MHz are often used for sensor devices.<br />(Behavior follows spi_master_config_t::bandRate_Bps in fsl_spi.h and SPI_MasterSetBaud() in fsl_spi.c) |
mode | SPISEL is specified in init() . |
bits | This is the transfer unit. 8 is usually specified. It can be set from 1 to 16. If 9 bits or more are specified, the byte array for data transfer is read in 2-byte units, requiring twice the amount of data. The first byte represents 8 bits from the LSB, and the second byte represents the remaining bits. (Behavior follows SPI_MasterTransferBlocking() in fsl_spi.h) |
ssel | This is the SPI SELECT. Specify 0 to 2. |
enum class E_PIN_CONF
enum class E_PIN_CONF : uint8_t {
NODEF = 0, // Not specified
PRIMARY = 1, // Primary assignment (PIO10/11)
ALT = 2 // Alternate assignment (PIO15/16)
};
// Type for assignments, comparisons, etc. between enum class and int types.
using wE_PIN_CONF = mwf::enum_wapper<E_PIN_CONF>;
This is an enumeration for specifying pin assignments.
enum class E_PIN_SSEL
enum class E_PIN_SSEL : uint8_t {
SSEL_VOID = 0, // Undefined
SSEL_PRIMARY, // Primary setting pin
SSEL_ALT, // Alternate setting pin
SSEL_SOFT = 0x10,
SSEL0_PIO3, // SSEL0 is software-controlled, using PIO3
SSEL1_PIO16, // SSEL1 is software-controlled, using PIO16
SSEL2_PIO17, // SSEL2 is software-controlled, using PIO17
SSEL1_PIO4, // SSEL1 is software-controlled, using PIO4
SSEL2_PIO13, // SSEL2 is software-controlled, using PIO13
};
This enumeration determines the arrangement of the SPI SELECT pins. The corresponding value is stored in spi::config::pin_ssel[3]
.
Set
pin_ssel[]
according to the number of devices used.- For one device, set
pin_ssel[0]
.pin_ssel[1]
andpin_ssel[2]
should beSSEL_VOID
. - For two devices, set
pin_ssel[0]
andpin_ssel[1]
.pin_ssel[2]
should beSSEL_VOID
. - For three devices, set
pin_ssel[0]
,pin_ssel[1]
, andpin_ssel[2]
.
- For one device, set
To specify hardware control, use
SSEL_PRIMARY
orSSEL_ALT
(andSSEL_VOID
). If you mix them, it will result in software control.
enum class E_SPI_DIR
enum class E_SPI_DIR {
MSB_FIRST = 0,
LSB_FIRST
};
This specifies the bit order. MSB_FIRST
is typically used.
enum class E_SPI_MODE
enum class E_SPI_MODE {
MODE_0_RISE = 0,
MODE_1_FALL = 1,
MODE_2_INV_FALL = 2,
MODE_3_INV_RISE = 3,
};
This specifies the SPI transfer mode. It determines the clock’s detection edge and whether the H/L value at that time is 0 or 1. Set this according to the connected device’s datasheet.
global_init_spi1_manager()
, global_deinit_spi1_manager()
static void global_init_spi1_manager(E_PIN_MAIN pin_conf = E_PIN_MAIN::PRIMARY);
static void global_deinit_spi1_manager();
These functions create and destroy the class object for using the SPI1 bus. During class object creation, you select the pin combination to use with pin_conf
. You can specify E_PIN_MAIN::PRIMARY
(value 0) or E_PIN_MAIN::ALT
(value 1) for the pin configuration.
init()
void init();
void init(spi::config& cnf);
void init(spi::config&& cnf);
This function initializes the SPI bus. By providing the cnf
parameter, you can set several configurations. If the parameter is omitted, it re-initializes with the previous settings.
- Even if you are software-controlling the select pin in your user program, you must specify at least one. The specified pin will be configured as a GPIO output. By calling
unset_ssel_auto()
, the library will no longer control that pin.
reconf()
void reconf();
This function re-applies the peripheral parameters. To access the internal settings, use spi::config& get_conf()
. Pin settings (pin_ssel[]
) are not reflected by this procedure.
set_data_width()
void set_data_width(uint8_t bits);
This function changes the transfer data width. It is a lighter procedure than reconf()
.
set|unset|get_ssel_auto()
void set_ssel_auto();
void unset_ssel_auto();
bool get_ssel_auto();
Sets, unsets, and gets the automatic control flag for the select pin.
- This is only effective when using software control.
- When
transfer_blocking()
is called, the SELECT pin is automatically set to LOW. It is set back to HIGH upon completion.
ssel_select()
void ssel_select(uint8_t select);
This function specifies the select pin. select
takes values of 0, 1, or 2, corresponding to SSEL0 through SSEL2.
- With hardware or software control and the automatic control flag (
set_ssel_auto()
) enabled, pin control is performed when the transfer API is called. - With software control, regardless of the automatic control flag, the SELECT pin is set to LOW immediately after the
ssel_select()
call. - With hardware control, it calls
reconf()
to re-initialize. This process has a high time cost, so if you frequently switch between devices for transfers, please use software control.
ssel_deselect()
void ssel_deselect();
This function deselects the select pins.
- With software control, all select pins are returned to a HIGH level.
- With hardware control, it does nothing.
- It does not change the pin specification from
ssel_select()
.
Other
bool has_init(); // Returns true if init() has been executed
spi::config& get_conf(); // Accesses internally stored configuration information
Pin Assignments
For E_PIN_CONF::PRIMARY
Signal | PIO Number | Description |
---|---|---|
SCK | 0 | Clock signal |
MOSI | 2 | SPIMOSI. TWELITE side is output, external SPI device side is input. |
MISO | 5 | SPIMISO. TWELITE side is input, external SPI device side is output. |
Select Pins
pin_ssel | E_PIN_SSEL | PIO | Remarks |
---|---|---|---|
SSEL0 pin_ssel[0] | SSEL_PRIMARY | 3 | |
SSEL_ALT | 16 | ||
SSEL0_PIO3 | 3 | Software-controlled | |
SSEL0_PIO16 | 16 | Software-controlled | |
SSEL1 pin_ssel[1] | SSEL_PRIMARY | 4 | |
SSEL_ALT | 14 | ||
SSEL1_PIO4 | 4 | Software-controlled | |
SSEL1_PIO14 | 14 | Software-controlled | |
SSEL1_PIO16 | 16 | Software-controlled (Cannot specify SSEL0_PIO16 ) | |
SSEL_VOID | Only use SSEL0 for selection | ||
SSEL2 pin_ssel[2] | SSEL_PRIMARY | 13 | |
SSEL2_PIO13 | 13 | Software-controlled | |
SSEL2_PIO17 | 17 | Software-controlled | |
SSEL_VOID | Only use SSEL0 and SSEL1 for selection |
- A maximum of three select pins can be set in order from
SSEL0
toSSEL1
andSSEL2
. - If any of the
pin_ssel[]
specifications are for software control, all select pins will be software-controlled by the library.
For E_PIN_CONF::ALT
Signal | PIO Number | Description |
---|---|---|
SCK | 15 | Clock signal |
MOSI | 17 | SPIMOSI. TWELITE side is output, external SPI device side is input. |
MISO | 18 | SPIMISO. TWELITE side is input, external SPI device side is output. |
Select Pins
pin_ssel | E_PIN_SSEL | PIO | Remarks |
---|---|---|---|
SSEL0 pin_ssel[0] | SSEL_PRIMARY | 16 | |
SSEL_ALT | 3 | ||
SSEL0_PIO3 | 3 | Software-controlled | |
SSEL0_PIO16 | 16 | Software-controlled | |
SSEL1 pin_ssel[1] | SSEL_PRIMARY | 14 | SSEL0 must be specified |
SSEL_ALT | 4 | ||
SSEL1_PIO4 | 4 | Software-controlled | |
SSEL1_PIO14 | 14 | Software-controlled | |
SSEL_VOID | Only use SSEL0 for selection | ||
SSEL2 pin_ssel[2] | SSEL_PRIMARY | 13 | |
SSEL_ALT | 5 | Note that this is also the PRG pin. | |
SSEL2_PIO5 | 5 | Software-controlled. Note that this is also the PRG pin. | |
SSEL2_PIO13 | 13 | Software-controlled | |
SSEL_VOID | Only use SSEL0 and SSEL1 for selection |
- A maximum of three select pins can be set in order from
SSEL0
toSSEL1
andSSEL2
. - If any of the
pin_ssel[]
specifications are for software control, all select pins will be software-controlled by the library.
class mwf::periph::spi
(sys_ev_handler
)
on_sleep()
As a procedure before sleep, the SPI is returned to an unused state. If it has been initialized by init()
, this state is saved.
on_wakeup()
If it was in an initialized state before sleep, it is re-initialized so that the SPI bus can be used.
4.2.10 - mwf_periph_wtimer - WTIMER, FRWT
mwf_periph_wtimer
- WWDT, FRWT
This implements the_wtimer
, a peripheral object that summarizes the procedures for using the wake-up timer.
With TWENET, this is used implicitly, so no initialization is required in the user’s program.
The wake-up timer counts down based on the 32768Hz crystal oscillator built into the module. For example, if the timer starts from 32768, the counter will reach 0 and an interrupt will occur after 1 second. It is typically used for waking up from sleep. Since the counter continues to count down even after waking up, you can calculate the elapsed time since waking up by reading the counter value.
There are two wake-up timer channels: channel 0 uses a 40-bit counter (used as a 32-bit counter in this library), and channel 1 uses a 28-bit counter.
The FRWT (Free Running Wake Timer) procedure, which uses the wake-up timer, is also included. By taking advantage of its ability to operate with low current consumption during sleep, one of the two wake-up timer channels can be kept running constantly, allowing it to be used as a counter for real-time. In TWENET, FRWT functions with a specific setting, which allows for efficient waiting for ADC initialization, etc., while FRWT is running.
TWENET uses channel 0 as the FRWT and channel 1 as the regular wake-up timer.
Code example
- include
#include "mwf_periph_wtimer.hpp"
class mwf::periph::wtimer
global_init_wtimer_manager()
, global_deinit_wtimer_manager()
static void global_init_wtimer_manager();
static void global_deinit_wtimer_manager();
These functions create and destroy the the_wtimer
class object.
init()
, deinit()
void init();
void deinit();
These functions initialize or terminate the wake-up timer.
- The
u32ms
parameter during initialization specifies the timeout in milliseconds (ms). If it is0
or omitted, the timeout will be 4000ms.
start()
, stop()
void start(uint8_t dev, uint32_t u32ct)
void stop(uint8_t dev)
These functions start or stop the wake-up timer.
- For
dev
, specify the device number of the wake-up timer to be used (WTIMER0_DEVICE
orWTIMER1_DEVICE
). - For
u32ct
, specify the initial count value. - If you specify a wake-up timer channel that is currently running as an FRWT, the function will do nothing.
read()
uint32_t read(uint8_t dev)
This function reads the count value of the wake-up timer.
- For
dev
, specify the device number of the wake-up timer to be used (WTIMER0_DEVICE
orWTIMER1_DEVICE
). - The value of a wake-up timer channel that is currently running as an FRWT cannot be read.
is_running()
bool is_running(uint8_t dev)
This function determines whether the wake-up timer is currently running.
- For
dev
, specify the device number of the wake-up timer to be used (WTIMER0_DEVICE
orWTIMER1_DEVICE
). - If you specify a wake-up timer channel that is currently running as an FRWT, it returns
false
.
set_interrupt()
void set_interrupt(uint8_t dev, bool b_enabled)
This function specifies whether the wake-up timer should generate an interrupt.
- For
dev
, specify the device number of the wake-up timer to be used (WTIMER0_DEVICE
orWTIMER1_DEVICE
). - Setting
b_enabled
totrue
enables interrupts. If this is not specified, an interrupt will not occur even when waking up from sleep. Note that oncetrue
has been specified for a wake-up timer, you cannot disable the interrupt by specifyingfalse
. - If you specify a wake-up timer channel that is currently running as an FRWT, the function will do nothing.
get_fired_status_on_wakeup()
uint8_t get_fired_status_on_wakeup()
This function is called after waking up from sleep. If the wake-up cause was a wake-up timer, the corresponding bit (WTIMER0_DEVICE_MASK
or WTIMER1_DEVICE_MASK
) will be set.
class mwf::periph::wtimer (sys_ev_handler)
on_sleep()
There are no special procedures.
on_wakeup()
This function confirms the wake-up cause, saves the information internally, and clears the interrupt status. The timer also does not stop.
FRWT related functions
freerun_start()
, freerun_stop()
void freerun_start(uint8_t dev)
void freerun_stop()
These functions start and stop the FRWT. The count value is incremented at 32768Hz, starting from 0 at the beginning.
- For
dev
, specify the device number of the wake-up timer (WTIMER0_DEVICE
orWTIMER1_DEVICE
).
freerun_is_running()
bool freerun_is_running()
Returns true
if the FRWT is running.
freerun_is_device()
bool freerun_is_device(uint8_t dev)
Returns true
if the specified device is the one running as an FRWT.
- For
dev
, specify the device number of the wake-up timer (WTIMER0_DEVICE
orWTIMER1_DEVICE
).
freerun_ct_get()
uint32_t freerun_ct_get()
Returns the FRWT’s count value. The FRWT’s count value is not the wake-up timer’s value itself, but is converted to an incrementing value from 0 (roughly a value with its sign inverted).
Count Value Calculation Functions
These functions convert the FRWT count value to milliseconds or calculate the difference between two count values.
freerun_ct_convert_msec()
uint32_t freerun_ct_convert_msec(uint32_t ct, uint32_t* dec_part = nullptr)
This function converts the FRWT count value ct
to milliseconds. If dec_part
is specified, it sets the value of the 1/10th digit to a value from 0 to 9.
freerun_ct_diff()
int32_t freerun_ct_diff(uint32_t val_past, uint32_t val_now)
This function calculates the difference between two count values. It is essentially val_now - val_past
, but it is calculated to account for cases where the counter returns to 0 after reaching its maximum value. Time differences up to half of the maximum counter value can be calculated, and if val_past
is older, it returns a positive value.
freerun_ct_diff_msec()
int32_t freerun_ct_diff_msec(int32 vdiff)
This function converts the counter difference vdiff
obtained from freerun_ct_diff()
to milliseconds.
freerun_ct_diff_usec()
int32_t freerun_ct_diff_usec(int32 vdiff)
int32_t freerun_ct_diff_usec(uint32_t val_past, uint32_t val_now)
This function converts the counter difference vdiff
obtained from freerun_ct_diff()
or the counter difference calculated from val_past
and val_now
to microseconds.
- Due to calculation, an
int32_t
overflow can occur (e.g., if the time difference exceeds approximately 2000 seconds).
4.2.11 - mwf_periph_wwdt - WWDT
mwf_periph_wwdt - WWDT
the_wwdt
, a peripheral object that summarizes the procedures for using the watchdog timer, is implemented.
With TWENET, this is used implicitly, so no initialization is required in the user’s program.
Code example
void setup_func() {
mwf::gobal_init_wwdt_manager();
the_wwdt.init(); // timeout in 4000ms approx.
}
// in some function called periodically (e.g. invoked by SysTick Timer.)
void do_every_tick() {
the_wwdt.refresh();
}
class mwf::periph::wwdt
global_init_wwdt_manager()
, global_deinit_wwdt_manager()
static void global_init_wwdt_manager();
static void global_deinit_wwdt_manager();
These functions create and destroy the the_wwdt
class object.
init()
, deinit()
void init(uint32_t u32ms = 0);
void deinit();
These functions initialize and stop the watchdog timer (*1).
- The
u32ms
parameter during initialization specifies the timeout in milliseconds (ms). If it is0
or omitted, the timeout will be 4000ms. - *1 Due to hardware limitations, a watchdog timer that has been started once cannot be stopped.
deinit()
is provided as a library procedure (e.g., when restarting the timer, you would executedeinit()
and then callinit()
again).
set_timeout()
void set_timeout(uint32_t u32ms);
This function changes the watchdog timer’s timeout duration. For u32ms
, specify the timeout duration in milliseconds (ms).
- The validity of
u32ms
is not validated. Whileinit()
used0
as a default value, the behavior of this function when0
is provided is undefined.
refresh()
void refresh();
This is the refresh function that must be called before the watchdog timer’s timeout.
class mwf::periph::wwdt (sys_ev_handler)
on_sleep()
Performs the WWDT stop procedure.
on_wakeup()
Performs the WWDT start procedure.
- If it was active before sleep, the WWDT is reactivated.
4.2.12 - class tick_counter - Stop Watch
class tick_counter
- Stop Watch
Used to measure very short processing times in the msec and usec ranges. It uses the microcontroller’s hardware counting function.
For this library code, it is recommended to keep its use experimental after sufficient verification. If measurement in units of approximately 30usec is sufficient, using the wake-up timer’s count value is simpler.
It controls the
CoreDebug->DEMCR
andDWT
registers.- It is believed that these registers are not intended for general, widespread use. While you may not experience major issues during temporary time measurements in development, their use in firmware at the final operational stage is not recommended.
It is possible to construct multiple
tick_counter
objects simultaneously.- The counting function used is a single one and is shared among the objects.
- The counting function is started when the first object is constructed and stopped when all objects are destroyed.
Example:
#include <mwf_stop_watch.hpp>
void some_func() {
// ...
// Start measurement 1
mwf::periph::tick_counter sw;
sw.lap(); // Start measurement 1 (although lap() is also called when sw is constructed, call it directly before the process for more precise measurement)
// ... // Process to be measured
sw.lap(); // End measurement 1
// Display value (Start measurement 1 to End measurement 1)
PRINTF("%dusec", sw.get_us());
// Next process
sw.lap(); // Start measurement 2
// ... // Process to be measured
sw.lap(); // End measurement 2
// Display value (Start measurement 2 to End measurement 2)
PRINTF("%dusec", sw.get_us());
}
_start_counter()
, _stop_counter()
static void _start_counter();
static void _stop_counter();
These functions start and stop the count timer using the CoreDebug feature.
tick_counter()
This is the constructor. If no other objects have been constructed, it starts the counter and also calls lap()
to begin measurement.
~tick_counter()
This is the destructor. It stops the counter when all class objects have been destroyed.
lap()
This function saves the previous count value and stores the count value at the time it was called.
The elapsed time is obtained with get_us()
.
4.2.13 - mwf-utils - utils
mwf_utils
Other utilities.
prepare_object()
template <class T>
static inline std::unique_ptr<T>& prepare_object(std::unique_ptr<T>& spobj, bool b_construct_if_null = true) {
if (!spobj && b_construct_if_null) {
spobj.reset(new T());
}
return spobj;
}
This function references an object of the smart pointer std::unique_ptr<>
. If the object has not been constructed, it is constructed using new T()
.
get_value_if()
// When getting a value from a function and proceeding with a process using that value
int v = some_func();
if (v != -1) {
// Do something with the value of v
printf("%d", v);
}
// Rewrite as follows
if (auto x = get_value_if::ne(some_func(), -1)) {
printf("%d", x.value());
}
As shown in the example above, this is a utility class for writing code that uses a function’s return value under a certain condition, by using a variable declaration within an if
statement.
In the example above, get_value_if::ne()
is used. The first parameter is a function call that returns a value, and the second parameter specifies the value for comparison. In this case, the if
block is evaluated only when the return value of some_func()
is not -1
. The types of the first and second parameters must be the same.
The following comparison expressions can be used: eq
, ne
, lt
, le
, gt
, ge
.
get_value_if::xx() (T is a type) | Condition | |
---|---|---|
eq(T lhs, const T rhs) | (lhs == rhs) | Returns true if the values are the same. |
ne (T lhs, const T rhs) | (lhs != rhs) | Returns true if the values are different. |
lt (T lhs, const T rhs) | (lhs < rhs) | Compares values, returns true if the value is smaller. |
le (T lhs, const T rhs) | (lhs <= rhs) | Compares values, returns true if the value is less than or equal to. |
gt (T lhs, const T rhs) | (lhs > rhs) | Compares values, returns true if the value is larger. |
ge (T lhs, const T rhs) | (lhs >= rhs) | Compares values, returns true if the value is greater than or equal to. |
Note: T
indicates a type (a type parameter in a template
construct).
4.3 - TWENETutils - TWENET Utility
TWENETutils - TWENET Utility
This library includes general algorithms and peripheral procedures. It corresponds to libTWENETutils.a
.
- Refer to the TWELITE NET API Reference “Utils Reference, etc.”
4.3.1 - utils.h
main()
, WarmMain()
utils.h
.utils.h
This section introduces the macros and functions available by including utils.h
.
S_OCTET(x)
Writes one byte to memory.
uint8 *q = &sTx.au8Data[0];
S_OCTET(0x12);
S_BE_WORD(0x1234);
S_BE_DWORD(0x12345678);
Declare uint8 *q
as a local variable and use it as a pointer to the memory area where you want to write data. q++
is executed after the assignment operator is evaluated.
S_BE_WORD(x)
Writes two bytes to memory.
uint8 *q = &sTx.au8Data[0];
S_OCTET(0x12);
S_BE_WORD(0x1234);
S_BE_DWORD(0x12345678);
Declare uint8 *q
as a local variable and use it as a pointer to the memory area where you want to write data. q+=2
is executed after the assignment operator is evaluated.
BE
stands for Big Endian, and LE
for Little Endian.
S_BE_DWORD(x)
Writes four bytes to memory.
uint8 *q = &sTx.au8Data[0];
S_OCTET(0x12);
S_BE_WORD(0x1234);
S_BE_DWORD(0x12345678);
Declare uint8 *q
as a local variable and use it as a pointer to the memory area where you want to write data. q+=4
is executed after the assignment operator is evaluated.
BE
stands for Big Endian, and LE
for Little Endian.
G_OCTET()
Reads one byte from memory and stores the value in a uint8
type variable.
uint8 *p = &sRx.au8Data[0];
uint8 u8data1 = OCTET();
uint16 u16data2 = G_BE_WORD();
uint32 u32data3 = G_BE_DWORD();
Declare uint8 *p
as a local variable and use it as a pointer to the memory area you want to read data from. p++
is executed after the =
operator is evaluated.
G_BE_WORD()
Reads two bytes from memory and stores the value in a uint16
type variable.
uint8 *p = &sRx.au8Data[0];
uint8 u8data1 = OCTET();
uint16 u16data2 = G_BE_WORD();
uint32 u32data3 = G_BE_DWORD();
Declare uint8 *p
as a local variable and use it as a pointer to the memory area you want to read data from. p+=2
is executed after the =
operator is evaluated.
BE
stands for Big Endian, and LE
for Little Endian.
G_BE_DWORD()
Reads four bytes from memory and stores the value in a uint32
type variable.
uint8 *p = &sRx.au8Data[0];
uint8 u8data1 = OCTET();
uint16 u16data2 = G_BE_WORD();
uint32 u32data3 = G_BE_DWORD();
Declare uint8 *p
as a local variable and use it as a pointer to the memory area you want to read data from. p+=4
is executed after the =
operator is evaluated.
BE
stands for Big Endian, and LE
for Little Endian.
ENCODE_VOLT(x)
This function converts a value from 2000 to 3600 into an 8-bit value.
- 1.95V to 2.80V is in 5mV increments.
- 2.81V to 3.65V is in 10mV increments.
// utils.h definition
#define ENCODE_VOLT(m) \
(m < 1950 ? 0 : \
(m > 3650 ? 255 : \
(m <= 2802 ? ((m-1950+2)/5) : ((m-2800-5)/10+171)) ))
...
uint16 u16Volt = 2860;
uint8 u8Volt_enc = ENCODE_VOLT(u16Volt);
uint16 u16Volt_dec = DECODE_VOLT(u8Volt_Enc);
Values from 2000 to 2800 are assigned to an 8-bit value in increments of 5, and values from 2800 onwards are assigned in increments of 10.
DECODE_VOLT(x)
This function converts the 8-bit value obtained from ENCODE_VOLT()
back to its original value.
- 1.95V to 2.80V is in 5mV increments.
- 2.81V to 3.65V is in 10mV increments.
// utils.h definition
#define DECODE_VOLT(i) \
(i <= 170 ? (1950+i*5) : (2800+(i-170)*10) )
...
uint16 u16Volt = 2860;
uint8 u8Volt_enc = ENCODE_VOLT(u16Volt);
uint16 u16Volt_dec = DECODE_VOLT(u8Volt_Enc);
Values from 2000 to 2800 are assigned to an 8-bit value in increments of 5, and values from 2800 onwards are assigned in increments of 10.
vPortAsInput(c)
Sets port c
as input.
#define vPortAsInput(c) vAHI_DioSetDirection(1UL << (c), 0)
vPortAsOutput(c)
Sets port c
as output.
#define vPortAsOutput(c) vAHI_DioSetDirection(0, 1UL << (c))
vPortSetHi(c)
Sets port c
to a high state.
#define vPortSetHi(c) vAHI_DioSetOutput(1UL << (c), 0)
vPortSetLo(c)
Sets port c
to a low state.
#define vPortSetLo(c) vAHI_DioSetOutput(0, 1UL << (c))
vPortSet_TrueAsLo(c, s)
Sets port c
to Lo if s
is TRUE, and to Hi if s
is FALSE.
#define vPortSet_TrueAsLo(c, s) vAHI_DioSetOutput((s) ? \
0 : 1UL << (c), s ? 1UL << (c) : 0)
bPortRead(c)
Reads port c
. Returns TRUE
if the level is low.
#define bPortRead(c) ((u32AHI_DioReadInput() & \
(1UL<<(c))) ? FALSE : TRUE)
u32PortReadBitmap()
Reads port c
. Returns TRUE
if the level is low.
#define u32PortReadBitmap() (u32AHI_DioReadInput())
A value of 1 in the bitmap represents Hi, and 0 represents Lo.
bPortCheckBitmap(bitmap, c)
This function returns TRUE
if the bit corresponding to port c
in the read bitmap is at a low level.
#define bPortCheckBitmap(bitmap, c) \
(bitmap & (1UL<<(c))) ? FALSE : TRUE)
vPortDisablePullup(c)
This function disables the pull-up for port c
.
#define vPortDisablePullup(c) vAHI_DioSetPullup(0x0, 1UL << (c))
_C
This macro is used to define a scope within a switch
statement. It is written as _C { … }
.
#define _C if(1)
// for example
switch(c) {
case 1:
_C {
uint8 u8work;
; // work
} break;
default:
}
LB
This is a newline string literal (CRLF).
Since it is a two-byte string literal, it cannot be used with vPutChar()
.
#define LB "\r\n"
vWait()
function
This function waits for a specified amount of time using a loop.
void vWait(uint32 c) {
static volatile uint32 u32ct = 0;
while (c-- > 0)
u32ct++;
}
The process is as described in the source code.
vAnalogueConfig()
, vAnalogueDisable()
These functions bundle the procedures for initializing and stopping the ADC function. They are intended for compatibility with existing code.
void vAnalogueConfig(void) {
#if defined(JN516x)
if (!bAHI_APRegulatorEnabled()) {
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE,
E_AHI_AP_INT_DISABLE,
E_AHI_AP_SAMPLE_4,
E_AHI_AP_CLOCKDIV_1MHZ,
E_AHI_AP_INTREF);
while (!bAHI_APRegulatorEnabled())
;
}
#elif defined(CPU_JN518X)
#endif
void vAnalogueDisable(void) {
#if defined(JN516x)
vAHI_ApConfigure(E_AHI_AP_REGULATOR_DISABLE,
E_AHI_AP_INT_DISABLE,
E_AHI_AP_SAMPLE_4,
E_AHI_AP_CLOCKDIV_1MHZ,
E_AHI_AP_INTREF);
#elif defined(CPU_JN518X)
#endif
}
Other Macro Definitions
// 64bit mac address
#define MAC_EXT_ADDR_TO_64BIT(ext) ((uint64)(ext.u32L) | (((uint64)(ext.u32H)) << 32))
// TIME COMPARE
#define u32TimeDiff(ref, now) (now - ref < 0x7FFFFFFF ? now - ref : )
// IO settings
#define vPortSetHi(c) vAHI_DioSetOutput(1UL << (c), 0)
#define vPortSetLo(c) vAHI_DioSetOutput(0, 1UL << (c))
#define vPortSet_TrueAsLo(c, s) vAHI_DioSetOutput((s) ? 0 : 1UL << (c), s ? 1UL << (c) : 0)
#define vPortAsInput(c) vAHI_DioSetDirection(1UL << (c), 0)
#define vPortAsOutput(c) vAHI_DioSetDirection(0, 1UL << (c))
#define bPortRead(c) ((u32AHI_DioReadInput() & (1UL<<(c))) ? FALSE : TRUE) // Lo as True
#define u32PortReadBitmap() (u32AHI_DioReadInput())
#define bPortCheckBitmap(bitmap, c) ((bitmap & (1UL<<(c))) ? FALSE : TRUE)
#define vPortDisablePullup(c) vAHI_DioSetPullup(0x0, 1UL << (c))
#if defined(JN516x) || defined(CPU_JN518X)
#define PORT_KIT_SW1 2
#define PORT_KIT_SW2 3
#define PORT_KIT_SW3 10
#define PORT_KIT_SW4 9
#define PORT_KIT_LED1 17
#define PORT_KIT_LED2 13
#define PORT_KIT_LED3 12
#define PORT_KIT_LED4 11
#endif
#define PORT_KIT_SW1_MASK (1UL << PORT_KIT_SW1)
#define PORT_KIT_SW2_MASK (1UL << PORT_KIT_SW2)
#define PORT_KIT_SW3_MASK (1UL << PORT_KIT_SW3)
#define PORT_KIT_SW4_MASK (1UL << PORT_KIT_SW4)
#define PORT_KIT_SW_ALL2_MASK (PORT_KIT_SW1_MASK | PORT_KIT_SW2_MASK)
#define PORT_KIT_SW_ALL4_MASK (PORT_KIT_SW1_MASK | PORT_KIT_SW2_MASK | PORT_KIT_SW3_MASK | PORT_KIT_SW4_MASK)
#define PORT_KIT_LED1_MASK (1UL << PORT_KIT_LED1)
#define PORT_KIT_LED2_MASK (1UL << PORT_KIT_LED2)
#define PORT_KIT_LED3_MASK (1UL << PORT_KIT_LED3)
#define PORT_KIT_LED4_MASK (1UL << PORT_KIT_LED4)
#define PORT_KIT_LED_ALL2_MASK (PORT_KIT_LED1_MASK | PORT_KIT_LED2_MASK)
#define PORT_KIT_LED_ALL4_MASK (PORT_KIT_LED1_MASK | PORT_KIT_LED2_MASK | PORT_KIT_LED3_MASK | PORT_KIT_LED4_MASK)
// UART related
#define WAIT_UART_OUTPUT(P) SERIAL_vFlush(P)
// IO clock (on JN514x, IO runs at 16Mhz regardless of CPU clock.
#if defined(JN516x)
#define u32IO_FREQ_HZ 16000000UL
#elif defined(CPU_JN518X)
//#define u32IO_FREQ_HZ 32000000UL
#define u32IO_FREQ_HZ 16000000UL
#endif
void vAnalogueConfig(void);
void vAnalogueDisable(void);
void vWait(uint32 c);
4.3.2 - Timer Library
Timer
library.Timer Library
tsTimerContext
A structure for configuration used by the Timer
library.
- Clear it to 0.
- Ensure it is statically allocated.
Type | Name | Explanation |
---|---|---|
uint8 | u8Device | Specifies the timer device (E_AHI_DEVICE_TIMER0 ..4). |
uint16 | u16Hz | Specifies the timer frequency in Hz. |
uint8 | u8PreScale | Sets the prescaler for the 16MHz clock. |
bool_t | bPWMOut | If TRUE , performs PWM output. |
bool_t | bDisableInt | If TRUE , disables interrupts. |
vTimerConfig()
Explanation
Initializes the Timer
.
Arguments
Type | Name | Description |
---|---|---|
tsTimerContext | psTC | The timer configuration structure. |
Return Value
None.
Sample
tsTimerContext sTimerApp; // global or static allocation
// set 64ticks/sec
memset(&sTimerApp, 0, sizeof(tsTimerContext));
sTimerApp.u8Device = E_AHI_DEVICE_TIMER0;
sTimerApp.u16Hz = 64;
sTimerApp.u8PreScale = 4; // 15625ct@2^4
vTimerStart()
Explanation
Starts the Timer
.
This function can also be called for a Timer
that has already been started. It is used when changing the duty cycle, etc.
Arguments
Type | Name | Description |
---|---|---|
tsTimerContext | psTC | The timer configuration structure. |
Return Value
None.
Sample
// initialize and start
vTimerConfig(&sTimerApp); // initialize
vTimerStart(&sTimerApp); // start
// change duty
sTimerPWM.u16Duty = 256; // set new duty ratio
vTimerStart(&sTimerPWM); // just start again to change duty
vTimerStop()
Explanation
Stops the operation of the Timer
.
Arguments
Type | Name | Description |
---|---|---|
tsTimerContext | psTC | The timer configuration structure. |
Return Value
None.
Sample
// just stop the timer
vTimerStop(&sTimerApp);
...
// restart
vTimerStart(&sTimerApp);
...
// now, disable timer completely
vTimerStop(&sTimerApp);
vTimerDisable(&sTimerApp);
vTimerDisable()
This function destroys the Timer
.
Arguments
Type | Name | Description |
---|---|---|
tsTimerContext | psTC | The timer configuration structure. |
Return Value
None.
Sample
// just stop the timer
vTimerStop(&sTimerApp);
...
// restart
vTimerStart(&sTimerApp);
...
// now, disable timer completely
vTimerStop(&sTimerApp);
vTimerDisable(&sTimerApp);
4.3.3 - fprintf Library
fprintf
.fprintf
Library
This is a simple implementation of fprintf
.
{{< hint color=“info” >}}
This library is provided for source code compatibility. For new implementations, it is recommended to use TWENETmcu/printf
.
{{< /hint >}}
Reference
TWENETmcu/printf
-printf
library (open source)TWENETstgs
-TWE_fprintf()
, etc.
tsFILE
A structure that defines the output destination specified by vfPrintf()
and vPutChar()
.
Members
Type | Name | Description |
---|---|---|
uint8 | u8Device | Specifies the serial port (E_AHI_UART_0 or E_AHI_UART_1 ). |
bool_t (*) (uint8 u8Device, uint8 u8Char) | bPutChar | A function pointer for output. For the SERIAL library, SERIAL_bTxChar() is prepared, so specify that. |
{% hint style=“info” %}
SERIAL_bTxChar()
puts the byte passed as u8Char
into the FIFO queue within the SERIAL
library.
By preparing your own output function, you can use this for outputting strings to destinations other than UART. {% endhint %}
Sample code
#include "serial.h"
#include "fprintf.h"
tsFILE sSerStream;
tsSerialPortSetup sSerPort;
void vSerialInit(uint32 u32Baud, tsUartOpt *pUartOpt) {
// initialize sSerPort
...
SERIAL_vInit(&sSerPort);
// for vfPrintf()
sSerStream.bPutChar = SERIAL_bTxChar;
sSerStream.u8Device = E_AHI_UART_0;
}
void vSerOut() {
vfPrintf(&sSerStream, "HELLO!");
}
Here is an example of the character LCD output code.
#include "serial.h"
#include "fprintf.h"
tsFILE sLcdStream;
// handle LCD display
PUBLIC bool_t LCD_bTxChar(uint8 u8Device, uint8 u8Data) {
int i;
switch (u8Data) {
case '\n':
...
}
void vInitHardware() {
/* Initialise the LCD */
vLcdReset(3, 0);
/* register for vfPrintf() */
sLcdStream.bPutChar = LCD_bTxChar;
sLcdStream.u8Device = 0xFF;
}
void vSomeOutput() {
vfPrintf(&sLcdStream, "Hello World!\n");
}
vfPrintf()
Explanation
This function outputs to the destination specified by the tsFILE
structure (UART) using printf
format.
Arguments
Type | Name | Description |
---|---|---|
tsFILE* | psStream | Output destination |
const char * | pcFormat | Output format |
… | Variable arguments |
Supported Formats
s | String |
---|---|
d | Integer (up to 32 bits) |
u | Unsigned integer (up to 32 bits) |
x | Hexadecimal. a-f are lowercase. |
X | Hexadecimal. A-F are uppercase. |
b | Bit sequence |
Return Value
None.
Sample
void cbToCoNet_vMain(void) {
while (!SERIAL_bRxQueueEmpty(sSerPort.u8SerialPort)) {
int16 i16Char;
i16Char = SERIAL_i16RxChar(sSerPort.u8SerialPort);
vfPrintf(&sSerStream, "\n\r## [%c] --> ", i16Char);
SERIAL_vFlush(sSerStream.u8Device);
...
}
}
vPutChar()
Explanation
This function outputs one byte to the destination specified by the tsFILE
structure (UART).
Arguments
Type | Name | Description |
---|---|---|
tsFILE* | psStream | Output destination |
uint8 | u8Char | Output byte |
Return Value
None
Sample
#define IS_ASC(c) ((c) >= 0x20 && (c) <= 0x7e)
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
uint8 u8i;
vfPrintf(&sSerStream, LB"RX(len=%d):[", pRx->u8Len);
for (i = 0; i < pRx->u8Len; i++) {
uint8 c = pRx->auData[i];
vPutChar(&sSerStream, IS_ASC(c) ? c : '.');
}
}
4.4 - TWENETcmpt - AHI Compatibility Layer
TWENETcmpt - AHI Compatibility Layer
This library is intended to provide compatibility with the AHI library.
- It aims to enable the build and operation of TweApps, not to achieve full compatibility.
- The implementation uses the TWENETmwf library (a C++ library implemented with the FSL library).
Below are notes regarding various definitions of the compatibility layer.
Link | Description |
---|---|
Common & Others | Miscellaneous functions |
ADC | ADC-related APIs |
GPIO | GPIO-related APIs |
PWM | PWM-related APIs |
I2C (SMBus) | I2C-related APIs |
SPI | SPI bus |
Random | Random number generation |
UART | UART-related APIs |
WDT | Watchdog Timer |
WTIMER | Wake Timer, FRWT |
OnChipTemp | On-chip temperature sensor (ADC) |
4.4.1 - AHI-Compatible Functions
AHI-Compatible Functions
Some of the AHI functions are implemented for source-level compatibility.
- This library is implemented using the TWENETmwf library, which aggregates procedures from the FSL drivers.
- This implementation is not intended to maintain complete compatibility.
- Functions with proprietary extensions have
_MW
appended to their names. - Notes and considerations known at the time of writing are documented here.
- Internal implementations may change without notice.
- For parameters mentioned in the explanations, only items requiring attention are described; for omitted parts, refer to the original AHI library manual.
- For topics specific to TWELITE GOLD, the FSL library, and MCU core behavior, refer to NXP’s JN5189 reference manual and the TWENETmcu library implementation.
The following describes the AHI-compatible functions. Some items such as SPI and I2C are documented in separate files.
General Functions
u32AHI_Init()
uint32 u32AHI_Init();
Performs initialization for the AHI library in principle, but in this library, only a subset of variables is initialized.
bAHI_SetClockRate(), u8AHI_GetSystemClkRate()
bool_t bAHI_SetClockRate(uint8 u8clk_code);
uint8 u8AHI_GetSystemClkRate();
Sets or retrieves the CPU clock speed.
The configured clock values differ significantly from those of TWELITE BLUE/RED, so caution is required.
u8clk_code | TWELITE BLUE/RED | TWELITE GOLD |
---|---|---|
0 | 4Mhz | 12Mhz |
1 | 8Mhz | 12Mhz |
2 | 16Mhz | 32Mhz |
3 | 32Mhz | 48Mhz |
4.. | Configurable | Ignored |
- Although clocks such as
kFROM1M_to_MAIN_CLK
can be configured in the fsl library, they are disabled here due to severe operational issues. - Using a debugger may interfere with clock changes.
- The default value is 2, corresponding to 32Mhz (TWELITE GOLD). (Reference: 16MHz on TWELITE BLUE/RED)
bAHI_Set32KhzClockMode()
bool_t bAHI_Set32KhzClockMode(uint8 u8mode);
Does nothing.
vAHI_CpuDoze()
static inline void vAHI_CpuDoze() { __WFI(); }
Enters the low-power DOZE state while waiting for interrupts. On TWELITE-GOLD, it issues WFI (Wait For Interrupt).
vAHI_SwReset()
static inline void vAHI_SwReset() { NVIC_SystemReset(); }
Performs a reset.
Power-Related Functions
u16AHI_PowerStatus()
uint16 u16AHI_PowerStatus();
This function reports the following bitmaps:
Bit | Description |
---|---|
bit0 | 1 when waking up from sleep |
bit1 | 1 when RAM was retained |
At POR, the value is 0
, and for normal wake-up from RAM-retention sleep, the value is 3
.
vAHI_BrownOutConfigure()
static inline void vAHI_BrownOutConfigure(
uint8 const u8VboSelect,
bool_t const bVboRstEn,
bool_t const bVboEn,
bool_t const bVboIntEnFalling,
bool_t const bVboIntEnRising) { ; } // DUMMY FUNC
This definition exists only to avoid compilation errors. The function itself does nothing.
About Sleep
void ToCoNet_vSleep(uint8 u8Device, uint32 u32Periodms, bool_t bPeriodic, bool_t bRamOff)
Sleep in the TWENET C library uses the ToCoNet_vSleep()
function.
Note: In the mwx library, use the_twelite.sleep()
.
- If
bRamOff
is set to TRUE, the system enters sleep mode without retaining any RAM segments. Even in this case,PM_POWER_DOWN
from the JN518x FSL library definitions is used, notPM_DEEP_DOWN
.
About Sleep Failures (TWELITE GOLD)
On TWELITE GOLD, the procedure for sleep transition (POWER_EnterPowerMode()
) in the semiconductor library occasionally fails, resulting in the device not entering sleep mode. To address this, the following measures are taken:
- When the semiconductor library procedure fails, the function exits immediately, but after a delay loop equivalent to 100 µsec (
DelayLoopN(100)
), the sleep procedure is retried. - If the above retry fails 3 times,
ToCoNet_vSleep()
enters an infinite loop, and a watchdog timer reset normally occurs. In our experience, 2 or 3 retries have not been observed, but we allow up to 3 retries as a precaution. - After executing the above sleep procedure, if the value of
extern uint8 g_twenet_power_down_fails;
is non-zero upon waking up from sleep, it indicates that retries were performed. However, this variable is reset when a watchdog timer reset occurs.
For internal processing
u32AppApiInit()
uint32
u32AppApiInit(PR_GET_BUFFER prMlmeGetBuffer,
PR_POST_CALLBACK prMlmeCallback,
void *pvMlmeParam,
PR_GET_BUFFER prMcpsGetBuffer,
PR_POST_CALLBACK prMcpsCallback,
void *pvMcpsParam);
Performs the initialization process for AppQAPI.
vAHI_RegEvMgr_MW()
void vAHI_RegEvMgr_MW();
Constructs the management object (mwf::the_sys_ev_manager
) for managing class objects in the TWENETmwf library.
vAHI_OnWakeup_MW(), vAHI_OnWakeupRamOff_MW()
void vAHI_OnWakeup_MW(bool_t b_init_2nd);
void vAHI_OnWakeupRamOff_MW(bool_t b_init_2nd);
This procedure is executed upon wake-up. Refer to the processing in twenet_main.c
of TWENETmcu.
- Executes the wake-up processing of class objects in the TWENETmwf library:
mwf::the_sys_ev_manager->on_wakeup()
. - Calls
vAHI_DioOnWakeup_MW()
to store the pins that triggered the wake-up. - If
b_init_2nd
is FALSE, it is called in the early stage of startup; if TRUE, it is called after a certain amount of initialization has been completed (beforecbAppWarmStart(TRUE)
is called).
vAHI_OnWakeupRamOff_MW()
is called when waking up from RAM non-retentive sleep.
- If
b_init_2nd
is FALSE, it is called in the early stage of startup; if TRUE, it is called after a certain amount of initialization has been completed (aftercbAppWarmStart(TRUE)
is called).
vAHI_OnSleep_MW()
vAHI_OnSleep_MW();
This procedure is executed before entering sleep.
- Executes the pre-sleep processing of class objects in the TWENETmwf library:
mwf::the_sys_ev_manager->on_sleep()
. - Calls
vAHI_DioOnSleep_MW()
to configure the DIO wake-up pins.
vAHI_DMAEnable_MW(), vAHI_DMADisable_MW()
void vAHI_DMAEnable_MW();
void vAHI_DMADisable_MW();
Enables or disables the DMA feature.
vAHI_DMADisable_MW()
does not perform any operation.
4.4.2 - ADC-Related AHI Functions and Explanations
ADC
Some parts related to AHI’s ADC (Analog-to-Digital Conversion) are implemented for the purpose of source code compatibility.
- This implementation is not intended to maintain full compatibility.
- Notes and considerations known at the time of writing are described here.
- Internal implementation details may change without notice.
Overview
The hardware specifications of the ADC vary depending on the model.
TWELITE BLUE | TWELITE RED | TWELITE GOLD | |
---|---|---|---|
Resolution (bits) | 10bit | 10bit | 12bit |
Full Scale | 2470mV | 2470mV | 3600mV |
Number of Channels (not supported by API) | 4 | 4 (2) | 4 (2) |
This library provides processing for using four channels (ADC0..3) and Vcc.
However, compatibility of conversion time or conversion data is not handled by the library; it is assumed that adjustments will be made in the application source.
For conversions up to 6 pins or for ADC combining multiple channels, the AHI library does not provide support; please use mwf::the_adc
directly.
Related: On-chip Temperature Sensor
Pins
PIO | Notes | |
---|---|---|
ADC0 | 15 | |
ADC1 | 14 | Shared with DIO8 |
ADC2 | 16 | |
ADC3 | 17 |
AHIcmpt_ADC.cpp
This library describes the differences from the AHI library for TWELITE BLUE/RED.
For API specifications, please also refer to the AHI library manual.
vAHI_ApConfigure()
void vAHI_ApConfigure(
bool_t bAPRegulator,
bool_t bIntEnable,
uint8 u8SampleSelect,
uint8 u8ClockDivRatio,
bool_t bRefSelect);
Initializes the ADC (mwf::the_adc
object construction and the_adc->init()
initialization).
- Specify
bAPRegulator
as TRUE to enable the ADC. If set to FALSE, the ADC is disabled. - Specify
bIntEnable
as TRUE to enable ADC interrupts. u8SampleSelect
andbRefSelect
are ignored.u8ClockDivRatio
is also currently not applied.- A stabilization wait process for the analog circuit using
bAHI_APRegulatorEnabled()
is required.
bAHI_APRegulatorEnabled()
bool_t bAHI_APRegulatorEnabled(void)
When the wake timer (FRWT) is not running (which is the default in the C library), this function performs a fixed delay process (300 µsec). In this case, it is recommended to call this function immediately after invoking vAHI_ApConfigure()
. Even if sufficient time has already passed, the fixed delay will still be executed.
When FRWT is enabled, the function performs the required waiting process based on the timer count value. If sufficient time has already passed, no additional waiting will be performed within this function.
vAHI_APRegisterCallback()
void vAHI_APRegisterCallback(PR_HWINT_APPCALLBACK prApCallback);
Registers an interrupt handler. This will be called when the ADC conversion is completed.
vAHI_AdcEnable()
void void vAHI_AdcEnable(
bool_t bContinuous,
bool_t bInputRange,
uint8 u8Source);
Configures the ADC conversion.
- If
bContinuous
is selected, continuous conversion is performed. However, since internal interrupts occur on each conversion, performance considerations are necessary. - Specifying
bInputRange
has no effect because the hardware does not support this feature. - During this call, the pin corresponding to
u8Source
is configured for ADC use. - If
bAHI_APRegulatorEnabled()
was not executed aftervAHI_ApConfigure()
and the waiting process was skipped, the waiting process will be performed within this call.
vAHI_AdcDisable()
void vAHI_AdcDisable(void);
Stops the ADC.
vAHI_AdcStartSample()
void vAHI_AdcStartSample(void);
Starts the ADC conversion.
- In principle, the initial state is set as input; however, strictly speaking,
the initial state is determined by the
BOARD_InitPins()
initialization in the TWENETmcu library’s pinmux.c.
bAHI_AdcPoll()
bool_t bAHI_AdcPoll(void);
Used for the polling wait process while(bAHI_AdcPoll());
to wait for ADC completion.
- After the ADC completion interrupt, this call returns FALSE only once.
u16AHI_AdcRead(), i16AHI_AdcRead_mv()
uint16 u16AHI_AdcRead(void);
int16 i16AHI_AdcRead_mv(void); // 非AHI独自関数
Reads the executed ADC value.
u16AHI_AdcRead()
returns the ADC value in 12-bit (0..4095). On error, it returns0xffff
.i16AHI_AdcRead_mv()
is a custom function not present in the AHI library. It returns the ADC value in mV, and on error, it returns-32768
.
s_adc_int_handler()
static void s_adc_int_handler(uint32_t a1, uint32_t a2);
A static function defined in AHIcmpt_ADC.cpp
that acts as an interrupt handler
when the ADC conversion completes, passing the interrupt to TWENET’s AppQApi.
- If a callback function is specified with
vAHI_APRegisterCallback()
, this handler will not be called.
Experimental Implementation
Batch Processing for Multiple Channels
// TWELITE GOLD only
// Uses the FSL driver feature to acquire ADC values from multiple channels in a single operation.
// Execute ADC (parameters are the same as vAHI_AdcEnable())
void vAHI_AdcEnableSeq(
bool_t bContinuous,
bool_t bInputRange,
uint32 u32MaskSource);
// Read ADC value
uint16 u16AHI_AdcReadSeq(
uint8 u8Source
);
// Read ADC value (in mV)
int16 i16AHI_AdcReadSeq_mv(
uint8 u8Source
);
sensor_driver, adc.c, adc.h
sensor_driver
is a set of processing functions used in existing TWEApps applications, providing a mechanism to abstract sensor processing. adc.c
and .h
describe the sequential processing for operating the on-chip ADC with sensor_driver
, including issuing a series of commands, waiting, and acquiring data. Additionally, TWENETmwx/sensors/legacy
contains implementations for several sensors other than ADC.
When migrating projects from TWELITE BLUE/RED to TWELITE GOLD, use the adjusted files stored in App_Twelite/Common
. However, since project contents may differ, modifications may be required as needed.
Source Name | Description |
---|---|
adc.c | ADC processing part (ADC value conversion adjusted for TWELITE GOLD’s range) |
adc.h | Definition part |
sensor_driver.c | Sensor processing abstraction part |
sensor_driver.h | Definition part |
Code Example
Please refer to the comments within the following code.
#include "sensor_driver.h"
#include "adc.h"
tsObjData_ADC sObjADC; // ADC management structure (data section)
tsSnsObj sADC; // ADC management structure (control section)
int16 a1,a2,ab; // Variables for storing results
...
// ADC initialization
vSnsObj_Init(&sADC);
vADC_Init(&sObjADC, &sADC, TRUE);
vADC_WaitInit(); // Wait for hardware initialization
...
// Specify the ports to measure with ADC (here: power supply voltage, ADC1, ADC2)
sObjADC.u8SourceMask = TEH_ADC_SRC_VOLT
| TEH_ADC_SRC_ADC_1 | TEH_ADC_SRC_ADC_2;
// Start ADC
vSnsObj_Process(&sADC, E_ORDER_KICK); // Start command
// Wait until processing of one ADC channel completes (=E_AHI_DEVICE_ANALOGUE interrupt)
// and call vSnsObj_Process() sequentially.
void cbToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap) {
switch (u32DeviceId) {
case E_AHI_DEVICE_ANALOGUE:
// ADC completion interrupt
vSnsObj_Process(&sADC, E_ORDER_KICK);
if (bSnsObj_isComplete(&sADC)) {
// All channels have finished processing.
// The values are stored as follows:
a1=sObjADC.ai16Result[TEH_ADC_IDX_ADC_1]; // ADC1 [mV]
a2=sObjADC.ai16Result[TEH_ADC_IDX_ADC_2]; // ADC2 [mV]
ab=sObjADC.ai16Result[TEH_ADC_IDX_VOLT]; // Power supply voltage [mV]
// Return to the initial state before ADC start
vSnsObj_Process(&sADC, E_ORDER_KICK);
// For continuous execution, call E_ORDER_KICK again
vSnsObj_Process(&sADC, E_ORDER_KICK);
}
break;
default:
break;
}
}
Functions
vSnsObj_Init()
void vSnsObj_Init(tsSnsObj *pSnsObj)
Initializes the sensor management structure. Call this function right before vADC_Init()
.
vADC_Init()
void vADC_Init(tsObjData_ADC *pData, tsSnsObj *pSnsObj, bool_t bInitAPR)
Initializes the ADC. Prepare the tsObjData structure (for storing results) and the tsSnsObj structure (for ADC management) in advance.
- If bInitAPR is TRUE, the ADC hardware is initialized. Since hardware initialization takes some time, always execute vADC_WaitInit() to wait for initialization.
vSnsObj_Process()
void vSnsObj_Process(tsSnsObj *pObj, teEvent eEv)
Advances the ADC processing. Specifically, this function is called each time the conversion for one ADC port is completed.
During this process, the ADC value is retrieved, converted to mV, and stored in the tsSnsObj
structure.
This process handles events for the state transitions managed by the tsSnsObj
structure. Immediately after calling this process, call bSnsObj_isComplete()
to check whether processing is complete. To return to the initial state, execute this process again with E_ORDER_KICK
as the argument (in other words, to run the ADC again, execute E_ORDER_KICK
twice after completion).
tsObjData_ADC
structure
This structure contains the specified ADC channels and the resulting voltage values.
u8SourceMask
: A bitmap specifying the ports for ADC. The specified ports become ADC targets.TEH_ADC_SRC_VOLT
: Power supply voltageTEH_ADC_SRC_ADC_1-4
: ADC1,2,3,4
u8InputRangeMask
: Specifies the range (0-Vref or 0-2Vref) for the ADC target ports. Specified ports use 0-Vref; unspecified ports use 0-2Vref.ai16Result[]
: Structure for storing ADC values. Results are stored as mV values.TEH_ADC_IDX_VOLT
: Power supply voltageTEH_ADC_IDX_ADC_1-4
: ADC1,2,3,4
4.4.3 - AHI Functions and Explanations for DIO (GPIO)
DIO (GPIO)
Some of the AHI functions related to DIO (GPIO) are implemented for source-level compatibility.
- This implementation is not intended to maintain full compatibility.
- Notes and considerations known at the time of writing are described here.
- Internal implementations may change without notice.
- For parameters mentioned in the explanations, only items requiring attention are described; refer to the original AHI library manual for omitted details.
- Two terms, PIO and DIO, are used in this explanation:
- PIO: Pin numbers defined for the semiconductor used in TWELITE GOLD. The FSL library and others use only these pin numbers.
- DIO: Pin numbers used in the AHI API for TWELITE BLUE/RED. To maintain source-level compatibility with TWELITE BLUE/RED, this library converts between DIO and PIO as needed.
Overview
The pin assignment architecture differs from that of TWELITE BLUE/RED. Here, pins used in TWELITE BLUE/RED are labeled as DIO0..19/DO0..1/ADC0…3, while the pin names for the semiconductor used in TWELITE GOLD are labeled as PIO0..21. For details about the pins, refer to the semiconductor datasheet for each module.
- Some pins on the module are not mapped one-to-one:
- PIO0 is shared with DIO11 and DO0.
- PIO14 is shared with DIO8 and ADC1.
- Regarding DIO interrupts, there are the following differences:
- DIO0..19 supported independent interrupts, but since this feature does not exist here, the GINT (group interrupt) feature is used to achieve similar behavior. (Another feature called PINT supports independent interrupts but only for up to four ports, so it is not used in this library.)
- Hardware interrupt detection is only available on both edges; internal interrupts occur on either edge.
- While running (not in sleep mode), whether to call the AHI interrupt handler is determined by the pin state after the interrupt occurs, so the fact that detection is on both edges is not apparent.
- The edge for wake-up from sleep cannot be specified.
Pin Assignment
DIO | DIO | PIO | Notes |
---|---|---|---|
DIO0 | 0 | 16 | |
DIO1 | 1 | 17 | |
DIO2 | 2 | 18 | |
DIO3 | 3 | 19 | |
DIO4 | 4 | 7 | |
DIO5 | 5 | 6 | |
DIO6 | 6 | 8 | |
DIO7 | 7 | 9 | |
DIO8 | 8 | 14 | Shared with ADC1 |
DIO9 | 9 | 12 | |
DIO10 | 10 | 4 | |
DIO11 | 11 | 0 | Shared with DO0 |
DIO12 | 12 | 13 | |
DIO13 | 13 | 1 | |
DIO14 | 14 | 10 | |
DIO15 | 15 | 11 | |
DIO16 | 16 | 20 | |
DIO17 | 17 | 21 | |
DIO18 | 18 | 2 | |
DIO19 | 19 | 3 | |
DO0 (PROG) | 0 | Shared with DIO11 | |
DO1 | 5 | ||
ADC2 | 14 | Shared with DIO8 | |
ADC1 | 15 |
AHIcmpt_Dio.cpp - Definitions and Constants
Definitions
#define BOARD_GPIO_PORT_MAX_PIN_COUNT 22 // Number of pins
#define BOARD_GPIO_PIN_TABLE_SIZE 24 // Rounded up to a multiple of 4 for 22 pins
g_twenet_ioport_remap_by_PIOn[]
const uint8 g_twenet_ioport_remap_by_PIOn[BOARD_GPIO_PIN_TABLE_SIZE];
(For internal library use) Table for converting PIO numbers to DIO numbers.
- 0x80: SPIMISO pin
- 0x90: ADC1 pin (analog only)
- 0xFF: Unused / undefined
g_twenet_ioport_remap_by_AHIn[]
const uint8 g_twenet_ioport_remap_by_AHIn[BOARD_GPIO_PIN_TABLE_SIZE];
(For internal library use) Table for referencing PIO numbers from AHI numbers.
AHIcmpt_Dio.cpp - Definitions
Variables
uint32 G_TWENET_IOPORT_OUTPUT_BM() = 0; // DIO bitmap for output ports
uint32 G_TWENET_IOPORT_INT_ENABLED_BM() = 0; // DIO bitmap for interrupt-enabled ports
uint32 G_TWENET_IOPORT_INT_RISING_BM() = 0; // DIO bitmap for rising-edge interrupt-enabled ports
uint32 G_TWENET_IOPORT_INT_FALLING_BM() = 0; // DIO bitmap for falling-edge interrupt-enabled ports
volatile uint32 G_TWENET_IOPORT_INT_STATUS() = 0; // DIO bitmap recording wake-up pins when woken by DIO interrupt
uint32 G_TWENET_IOPORT_WAKE_STATUS() = 0; // DIO bitmap storing I/O interrupt sources at wake-up
- Each DIO bitmap corresponds bit n to DIOn (e.g., for DIO0 and DIO3, use
(1UL << 0) | (1UL << 3)
).
check_pio(), get_pio(), get_dio()
static inline bool check_pio(uint8 u8pio);
static inline uint8 get_pio(const uint8 u8dio);
static inline uint8 get_dio(const uint8 u8pio);
check_pio()
: An inline function that checks whether the specified PIO number is valid and not already used by another peripheral.get_pio()
: Returns the PIO number corresponding to the specified DIO number. Returns0xff
if the assignment is invalid.get_dio()
: Returns the DIO number corresponding to the specified PIO number. Returns0xff
if the assignment is invalid.
s_gpio_int_handler()
static void s_gpio_int_handler(uint32 bm_pio, uint32 bm_pio_changed, void* p_data);
Interrupt handler function internally called when a DIO interrupt occurs.
- If there is a pin change, interrupt information is sent via AppQAPI using
__twenet_vAppQApiPostHwIntT()
.
AHIcmpt_Dio.cpp - AHI Function Definitions
vAHI_DioSetDirection()
void vAHI_DioSetDirection(
uint32 u32Inputs,
uint32 u32Outputs);
Configures the input/output direction of ports.
- In principle, ports are set to input state at initialization, but strictly speaking, the initial state is defined by the
BOARD_InitPins()
initialization in the TWENETmcu library’s pinmux.c.
vAHI_DioSetOutput()
void vAHI_DioSetOutput( // u32On:HIGH, u32Off::LOW
uint32 u32On,
uint32 u32Off);
Changes the output state of ports. u32On
is the DIO bitmap for pins to set HIGH, and u32Off
is the DIO bitmap for pins to set LOW.
- When multiple pins are specified, the changes are not simultaneous.
- This is because, in the internal implementation, each pin is set individually within a loop.
vAHI_DioSetPullup()
void vAHI_DioSetPullup(
uint32 u32On,
uint32 u32Off);
Configures the pull-up state.
- In principle, the default is pull-up enabled, but strictly speaking, the initial state is defined by the
BOARD_InitPins()
initialization in the TWENETmcu library’s pinmux.c.
u32AHI_DioReadInput()
uint32 u32AHI_DioReadInput(void);
Retrieves the state of all ports at once.
- The return value is a bitmap representing the state of all ports: bits set to
1
indicate HIGH level, and bits set to0
indicate LOW level. - The values for non-existent DIO numbers or ports used by peripherals are undefined.
vAHI_DioWakeEnable()
void vAHI_DioWakeEnable(
uint32 u32Enable,
uint32 u32Disable);
Starts DIO interrupts. u32Enable
specifies the DIO bitmap for adding interrupt handling, and u32Disable
specifies the DIO bitmap for removing interrupt handling. Additionally, you must specify the interrupt edge for the enabled pins using vAHI_DioWakeEdge()
.
- The behavior is undefined when specifying pins that are not configured as inputs (e.g., output pins or pins assigned to other peripheral functions).
vAHI_DioWakeEdge()
void vAHI_DioWakeEdge(
uint32 u32Rising,
uint32 u32Falling);
Configures the interrupt pins. This call sets both rising and falling edges for the specified pins at once. Note that you cannot add or remove edges individually.
Although the function name contains “Wake,” it configures both runtime interrupt handling and wake-up-from-sleep behavior.
- If the same pin is specified for both
u32Rising
andu32Falling
, interrupts occur on both edges due to the design principle. (However, since this is not a valid AHI setting, it is outside the scope of operation verification.) - During interrupt operation,
vAHI_DioWakeEnable()
is called internally for reconfiguration. - The behavior is undefined when specifying pins that are not configured as inputs (e.g., output pins or pins assigned to other peripheral functions).
- For wake-up from sleep, the interrupt edge is always set to both edges.
u32AHI_DioWakeStatus()
uint32 u32AHI_DioWakeStatus(void);
Returns the bitmap of pins that triggered the wake-up during a DIO interrupt.
- Internally, it returns the value of
__twenet_ioport_int_status
at the time of the call. After the call, the value is set to0
.
bAHI_DoEnableOutputs()
static inline bool_t bAHI_DoEnableOutputs(bool_t bEnableDO) {
return bAHI_DoEnableOutputsEx_MW(bEnableDO, bEnableDO);
}
Configures the DO0 and DO1 pins as output.
- Both DO0 and DO1 are configured as output.
- To configure only one pin, call
bAHI_DoEnableOutputsEx_MW()
.- DO1 (PIO5) is assigned to the pin used to determine transition to program mode (ISP_ENT) at startup, so it requires attention in hardware design. Unless there is a special reason, it is recommended to use a different pin.
- DO0 (PIO0) is also assigned to DIO11, so if both are used, code adjustments (excluding control of one side) are required.
vAHI_DoSetDataOut()
void vAHI_DoSetDataOut(
uint8 u8On,
uint8 u8Off);
Configures output settings for DO0 (PIO0) and DO1 (PIO1).
- DO0 is specified by bit0 (0x1), and DO1 is specified by bit1 (0x2) in the bitmap.
- Setting a bit in
u8On
sets the output to HIGH level, while setting it inu8Off
sets the output to LOW level.
vAHI_DoSetPullup()
void vAHI_DoSetPullup(
uint8 u8On,
uint8 u8Off);
Does nothing.
AHIcmpt_Dio.cpp - AHI Extended API
Functions with the _MW
suffix are custom extensions not present in the AHI library.
bAHI_DoEnableOutputsEx_MW()
bool_t bAHI_DoEnableOutputsEx_MW(
bool_t bEnableDO0, bool_t bEnableDO1);
Configures DO0 and DO1 as outputs.
This function was added because bAHI_DoEnableOutputs()
configures both ports simultaneously.
vAHI_DioInterruptDisablePinsIntWhenChanged_MW(), vAHI_DioInterruptReavtivate_MW()
void vAHI_DioInterruptDisablePinsIntWhenChanged_MW(bool_t bSet);
void vAHI_DioInterruptReavtivate_MW();
Temporarily disables interrupts for pins where an interrupt has been detected.
- When called with
bSet
set to TRUE, interrupts for the affected pins are temporarily disabled when a DIO interrupt occurs. - For inputs such as mechanical buttons with significant chattering, enable this setting and call
vAHI_DioInterruptReavtivate_MW()
after a certain time has passed since the interrupt to resume interrupts.
vAHI_DioOnSleep_MW()
void vAHI_DioOnSleep_MW();
An internal processing function not intended to be called by users.
It handles DIO interrupt-related processing before entering sleep, specifically configuring the DIO wake-up pins.
vAHI_DioOnWakeup_MW()
void vAHI_DioOnWakeup_MW(bool_t b_init_2nd);
An internal processing function not intended to be called by users.
It handles DIO interrupt-related processing at wake-up and stores the pins that triggered the wake-up.
- When called with
b_init_2nd
set tofalse
, it runs at the very early stage of theWarmMain()
process to identify the wake-up sources. - It is then called again with
true
just before the call tocbAppWarmStart(TRUE)
.
vAHI_DioRetentionRelease_MW()
void vAHI_DioRetentionRelease_MW();
Releases the DIO output state retention after waking up from sleep.
This function is used when waking from RAM-OFF sleep and inside cbAppColdStart()
.
On JN518X, the register setting (SYSCON->RETENTIONCTRL
) to retain DIO output states is configured before entering sleep.
DIO pins with output settings retain their states as configured in the register, and after waking from sleep, the output states remain until the register settings are changed. Calling this function releases the output state retention.
To restore the same configuration as before sleep, call vAHI_DioSetDirection()
or vAHI_DioSetOutput()
before calling this function to explicitly configure the output settings. This is necessary because DIO internal registers are cleared during sleep.
After the call to cbAppColdStart()
, the TWENETmcu library performs the same process as this function. To avoid unintended HI/LO transitions on ports, configure the port outputs inside cbAppColdStart()
.
Others
Notes When Not Using This Library
Do not call functions from this library. Even if you do not call them, this library still depends on the TWENETmcu and TWENETlib libraries.
Refer to the following to resolve dependencies:
- Regarding interrupt pins when performing sleep procedures:
- You need to adjust
vAHI_DioOnSleep_MW()
andvAHI_DioOnWakeup_MW()
.- These two functions are called from
vAHI_OnSleep_MW()
andvAHI_OnWakeup_MW()
in TWENETcmpt.
- These two functions are called from
- The
vAHI_OnSleep_MW()
function depends on the closed-source TWENETlib library.- In
vAHI_DioOnSleep_MW()
, specify the PIO bitmap for wake-up interrupt detection in__twenet_ioport_int_status
. It is applied insideToCoNet_vSleep()
to execute sleep properly.
- In
vAHI_OnWakeup_MW()
andvAHI_DioOnWakeup_MW()
are called within the TWENETmcu library source. Modify the processing as needed.
- You need to adjust
4.4.4 - AHI Functions and Explanations for Timer (PWM)
Timer (PWM)
Some parts of the AHI Timer-related APIs are implemented for source code compatibility.
- This implementation is not intended to maintain full compatibility.
- Notes and considerations known at the time of writing are described here.
- Internal implementations may change without notice.
- For parameters mentioned in the explanations, only items requiring attention are described; for omitted details, refer to the original AHI library manual.
AHI APIについて
vAHI_TimerFineGrainDIOControl()
void vAHI_TimerFineGrainDIOControl(uint8 u8BitMask)
Specifies the bitmask to disable output pins. Only the bits corresponding to TIMER_0 … TIMER_4 are valid.
- Call this function before executing
vAHI_TimerEnable()
. - Even if output is enabled in the parameters of
vAHI_TimerEnable()
, pins set to be disabled by this function will be treated as output-disabled.
vAHI_TimerAssignPIOPin_MW()
void vAHI_TimerAssignPIOPin_MW(
uint8 u8_timer_id,
uint8 u8_pin_id)
This function is specific to TWELITE GOLD.
Specifies the PIO number of the pin to be used with the specified timer device (u8_timer_id
).
Each PIO number is linked to a specific PWM channel. Some PIO numbers do not support PWM. Depending on how you specify them, it is possible to create conflicting settings, such as using the same PWM channel multiple times. Refer to the pin assignment table for mapping between PIO numbers and PWM channels.
u8_timer_id
specifies the target timer device (E_AHI_DEVICE_TIMER0-4
).- Settings in
vAHI_TimerFineGrainDIOControl()
are also valid, but output enable/disable is controlled bybOutputEnable
invAHI_TimerEnable()
. - Even if output is disabled and only timer interrupts are used, specify the pin number corresponding to the PWM channel to be used.
This is a custom function of this library.
vAHI_TimerEnable()
void vAHI_TimerEnable(
uint8 u8_timer_id,
uint8 u8Prescale,
bool_t bIntRiseEnable,
bool_t bIntPeriodEnable,
bool_t bOutputEnable)
Enables the timer.
- If
bIntRiseEnable == TRUE
, it is treated asbIntPeriodEnable == TRUE
. - Even if
bOutputEnable == TRUE
is set, if the pin is disabled byvAHI_TimerFineGrainDIOControl()
, it is treated asFALSE
. - The behavior is undefined if this function is called again for a timer ID that has already been enabled.
When Hardware Resource Conflicts Occur
Due to hardware differences from TWELITE BLUE/RED, not all timer devices can be used in the same way. Refer to the pin assignment section described later for details.
- If PWM output is enabled, software-based PWM output emulation will be performed.
- If PWM output is disabled, the purpose is limited to timer interrupts, so the available PWM3 or PWM5 will be used without pin output.
- No API or procedure is provided to check whether the above assignment has been made.
vAHI_TimerDisable()
void vAHI_TimerDisable(uint8 u8_timer_id)
Disables the timer.
- The output port is reverted to input (the pull-up setting is not changed).
vAHI_TimerDisable()
void vAHI_TimerDisable(uint8 u8_timer_id)
Disables the timer.
- The output port is reverted to input (the pull-up setting is not changed).
vAHI_TimerConfigure()
void vAHI_TimerConfigure(
uint8 u8_timer_id,
bool_t bInvertPwmOutput,
bool_t bGateDisable)
Modifies the timer settings.
- Configures
bInvertPwmOutput
. bGateDisable
is ignored.
vAHI_TimerStartRepeat()
void vAHI_TimerStartRepeat(
uint8 u8_timer_id,
uint16 u16Hi,
uint16 u16Lo)
Starts the timer.
- This function can also be called while the timer is running and is used to change the PWM duty cycle settings.
vAHI_TimerStop()
void vAHI_TimerStop(uint8 u8_timer_id)
Stops the timer.
vAHI_TimerSetLocation()
void vAHI_TimerSetLocation(
uint8 u8Timer,
bool_t bLocation,
bool_t bLocationOverridePWM3andPWM2)
Changes the pin assignment.
- Call this function before executing
vAHI_TimerEnable()
.
vAHI_TimerXRegisterCallback
PUBLIC void vAHI_Timer0RegisterCallback(
PR_HWINT_APPCALLBACK prTimer0Callback);
PUBLIC void vAHI_Timer1RegisterCallback(
PR_HWINT_APPCALLBACK prTimer1Callback);
PUBLIC void vAHI_Timer2RegisterCallback(
PR_HWINT_APPCALLBACK prTimer2Callback);
PUBLIC void vAHI_Timer3RegisterCallback(
PR_HWINT_APPCALLBACK prTimer3Callback);
PUBLIC void vAHI_Timer4RegisterCallback(
PR_HWINT_APPCALLBACK prTimer4Callback);
The interrupt handler registration functions are not implemented. The interrupt handler is invoked via AppQAPI.
If you want to define a custom interrupt handler, implement the WEAK
-defined handler functions below.
Refer to the implementation in AHIcmpt_TImers.cpp
.
At a minimum, you need to call PWM_ClearStatusFlags(PWM, kPWM_PwmX);
.
WEAK void PWM0_DriverIRQHandler(void); // MONO WIRELESS, DEFINED AS WEAK FUNCTION.
WEAK void PWM1_DriverIRQHandler(void);
WEAK void PWM2_DriverIRQHandler(void);
WEAK void PWM3_DriverIRQHandler(void);
WEAK void PWM4_DriverIRQHandler(void);
WEAK void PWM5_DriverIRQHandler(void);
WEAK void PWM6_DriverIRQHandler(void);
WEAK void PWM7_DriverIRQHandler(void);
WEAK void PWM8_DriverIRQHandler(void);
WEAK void PWM9_DriverIRQHandler(void);
Other Functions
void vAHI_TimerClockSelect(
uint8 u8Timer,
bool_t bExternalClock,
bool_t bInvertClock);
void vAHI_TimerStartSingleShot(
uint8 u8Timer,
uint16 u16Hi,
uint16 u16Lo);
These are either undefined functions or dummy functions that do nothing.
About Output Pins
- Output pins are initialized for PWM use when calling
vAHI_TimerEnabled()
. - Output pins are reset to input ports (without changing pull-up settings) when calling
vAHI_TimerDisable()
.
About Interrupts
Interrupts at intermediate output transition points within a cycle are not supported. Only interrupts for each full cycle are supported.
Interrupt Handlers
Interrupt handlers are only supported in the standard TWENET callbacks cbToCoNet_u8HwInt()
and cbToCoNet_vHwEvent()
.
Additional handlers cannot be registered.
If you want to define individual handlers, define the PWMx_IRQHandler()
functions separately.
In this case, events will not be reported to TWENET from the defined handler.
Pin Assignment
Pin assignment can be configured individually for each TIMER_ID, but due to hardware differences in TWELITE BLACK, assignments may be difficult in some cases.
Standard
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 12 | 16 | 13 | 15 | 19 |
AHI DIO## | 10 | 11 | 12 | 13 | 17 |
PIO## | 4 | 0 | 13 | 1 | 21 |
PWM channel | 4 | 0 | 2 | 1 | 9 |
When Using DO1,2 in Standard Mode
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 12 | 16 | 1 | 2 | 19 |
AHI DIO## | 10 | 11 | DO0 | DO1 | 17 |
PIO## | 4 | 0 | 0 | 5 | 21 |
PWM channel | 4 | 0 | 0 | N/A | 9 |
- TIMER_1 and TIMER_2 assignments conflict.
- The output pin for TIMER_3 does not have hardware timer functionality.
Secondary Assignment
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 6 | 7 | 8 | 9 | 10 |
AHI DIO## | 4 | 5 | 6 | 7 | 8 |
PIO## | 7 | 6 | 8 | 9 | 14 |
PWM channel | 7 | 6 | 8 | 9 | 1 |
When Using DO1,2 in Secondary Assignment
AHI TIMER ID | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
SMD PIN## | 6 | 7 | 1 | 9 | 10 |
AHI DIO## | 4 | 5 | DO0 | DO1 | 8 |
PIO## | 7 | 6 | 0 | 5 | 14 |
PWM channel | 7 | 6 | 0 | N/A | 1 |
- The output pin for TIMER_3 does not have hardware timer functionality.
Others
Behavior When Pin Assignment Conflicts Occur
- If a pin configured for PWM output has a conflict (e.g., the pin does not support PWM), software emulation will be used.
- The software emulation controls the output under the system timer (SysTick) interrupt, using 16 clocks per cycle. If running at 1 kHz, the PWM period is 1000/16 ≈ 62 Hz.
- If a pin without PWM output configured has a conflict (e.g., duplicate PWM device numbers), the available PWM3 or PWM5 is assigned. PWM interrupts will operate even without pin output.
When Not Using This Library’s PWM Features
- Do not call AHI timer-related APIs (
?AHI_Timer???
).- Calling these APIs creates processing objects for AHI compatibility. Behavior is undefined if you then call APIs defined in
fsl_pwm.h
in this state.
- Calling these APIs creates processing objects for AHI compatibility. Behavior is undefined if you then call APIs defined in
- Define
PWM0_IRQHandler()
…PWM9_IRQHandler()
separately. Since these are specified withweak
linkage, your application’s non-weak
definitions will take precedence at link time.
Behavior on Wake from Sleep
- For RAM-retention sleep, the PWM output state immediately before sleep is restored. For RAM-off sleep, normal DIO initialization is performed.
Related AHI APIs
void vAHI_TimerFineGrainDIOControl(
uint8 u8BitMask);
PUBLIC void vAHI_TimerConfigure(
uint8 u8Timer,
bool_t bInvertPwmOutput,
bool_t bGateDisable);
PUBLIC void vAHI_TimerEnable(
uint8 u8Timer,
uint8 u8Prescale,
bool_t bIntRiseEnable,
bool_t bIntPeriodEnable,
bool_t bOutputEnable);
PUBLIC void vAHI_TimerDisable(
uint8 u8Timer);
PUBLIC void vAHI_TimerClockSelect(
uint8 u8Timer,
bool_t bExternalClock,
bool_t bInvertClock);
PUBLIC void vAHI_TimerStartRepeat(
uint8 u8Timer,
uint16 u16Hi,
uint16 u16Lo);
PUBLIC void vAHI_TimerStop(
uint8 u8_timer_id);
PUBLIC void vAHI_TimerSetLocation(
uint8 u8Timer,
bool_t bLocation,
bool_t bLocationOverridePWM3andPWM2);
※ Some function names are redefined by macros.
※ The timer library in utils.h
also uses the above APIs.
Example Handler Definitions
Minimal definitions including the essential steps.
void PWM0_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm0); }
void PWM1_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm1); }
void PWM2_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm2); }
void PWM3_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm3); }
void PWM4_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm4); }
void PWM5_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm5); }
void PWM6_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm6); }
void PWM7_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm7); }
void PWM8_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm8); }
void PWM9_IRQHandler(void) { PWM_ClearStatusFlags(PWM, kPWM_Pwm9); }
- When you define these functions, interrupts/events will not be forwarded to TWENET.
About This Library’s Implementation
- The main implementation code is in
AHIcmpt_Timer.cpp
. - The above code references
_periph_pwm.hpp
and_periph_pwm.cpp
. These are class libraries that consolidate procedures using the platform drivers (driver/fs_???
).
4.4.5 - Explanation of SMBus.c,h Defining SMBUS (I2C)-Related Procedures
SMBUS (I2C)
In many sample and application codes using TWENET, the I2C bus is typically not accessed directly through the low-level AHI library procedures.
Instead, a set of simplified read/write functions defined in SMBus.c
and SMBus.h
is used.
The following is a list of the function names provided:
void vSMBusInit(void);
void vSMBusInit_setClk(uint32 u32Clk);
void vSMBusDeInit();
void vSMBusDeInit(void);
bool_t bSMBusWrite(uint8 u8Address, uint8 u8Command,
uint8 u8Length, uint8* pu8Data);
bool_t bSMBusSequentialRead(uint8 u8Address, uint8 u8Length,
uint8* pu8Data);
SMBus.c SMBus.h
These are a set of functions summarizing typical I2C procedures, with source code stored in TWENETmwx/source/sensors/legacy
.
- If the TWENETmwx library is not linked (C project), copy and use this source code.
vSMBusInit()
void vSMBusInit(void);
Initializes the I2C bus.
The pins used are DIO14 (CLK) and DIO15 (DATA), with a clock frequency of 100 Kbps.
vSMBusInit_setClk(uint32)
{{{cpp {noln=true} void vSMBusInit_setClk(uint32 u32Clk); }}}
Using this function instead of vSMBusInit()
initializes the I2C bus with the clock specified by u32clk
.
- If
u32clk >= 7
andu32clk <= 255
⇒ Initializes with clock frequency3200000ul / (u32clk + 1)
. For example, specifying31
gives 100 kHz, and7
gives 400 kHz. - If
u32clk >= 12500
andu32clk <= 400000
⇒ Initializes withu32clk
directly. - Otherwise ⇒ Undefined behavior.
※ The actual frequency will be the closest available based on the hardware clock divisor. For detailed calculations, refer to the source code (for TWELITE GOLD, see NXP’s FSL library specifications).
// Implementation for TWELITE GOLD
PUBLIC void TWENET_smbus_vSMBusInit_setClk(uint32_t u32clk)
{
...
if (u32clk >= 7 && u32clk <= 255) { // given by divisor
u32clk = 3200000ul / (u32clk + 1);
}
if (u32clk < 12500ul || u32clk > 400000ul) {
u32clk = 100000ul;
}
// initialize the I2C
//... rest of the implementation
_conf.baudRate_bps = u32clk;
I2C_MasterGetDefaultConfig(&_conf); // FSL library function
}
// Implementation for TWELITE BLUE/RED
void vSMBusInit_setClk(uint32 u32Clk)
{
/* convert clock to clock divisor */
if (u32Clk > 255) {
u32Clk = (3200000UL / u32Clk) - 1;
}
if (u32Clk < 7 || u32Clk > 255) u32Clk = 31; // set 100kHz
/* run bus at specified value */
vAHI_SiMasterConfigure(TRUE, FALSE, u32Clk);
// 16/[(PreScaler + 1) x 5]MHz
// --> 31:100KHz, 7:400KHz, 47:66KHz
}
vSMBusDeInit()
void vSMBusDeInit();
Stops the use of the I2C bus.
- For TWELITE BLUE/RED, calls
vAHI_SiMasterDisable()
. - For TWELITE GOLD, stops the I2C bus usage and restores DIO14 and DIO15 pins to the TWENET library’s initial configuration (input ports with pull-up).
bSMBusWrite()
bool_t bSMBusWrite(
uint8 u8Address,
uint8 u8Command,
uint8 u8Length,
uint8* pu8Data)
Performs a write operation on the I2C bus.
u8Address
⇒ Specifies the device address on the I2C bus.u8Command
⇒ Specifies the command (first transfer byte) for the write operation.u8Length
⇒ Number of subsequent bytes. If0
, only the command byte is transferred. If greater than0
,pu8Data
must be defined.pu8Data
⇒ Pointer to the memory area containing the bytes to be transferred.
Returns TRUE
if the transfer succeeds, and FALSE
if it fails.
bSMBusSequentialRead()
bool_t bSMBusSequentialRead(
uint8 u8Address,
uint8 u8Length,
uint8* pu8Data)
Performs a read operation on the I2C bus.
u8Address
⇒ Specifies the device address on the I2C bus.u8Length
⇒ Specifies the number of bytes to read (must be 1 or more).pu8Data
⇒ Pointer to the memory area where the read bytes will be stored.
Returns TRUE
if the transfer succeeds, and FALSE
if it fails.
Others
Handling During Sleep
For TWELITE BLUE/RED, hardware reinitialization is required after waking from sleep.
IfvSMBusDeInit()
is not called, the pin state is undefined (or follows the JN516x peripheral specification).
You can reinitialize by callingvSMBusInit()
orvSMBusInit_setClk()
again.For TWELITE GOLD, the behavior is as follows:
- RAM ON (normal) sleep: If the I2C bus was initialized before sleep, it will be reinitialized upon waking. If the I2C bus was not in use, normal general-purpose IO wake-up handling will apply.
- RAM OFF (deep) sleep: Upon waking, TWENET will reinitialize the pins as input pins with pull-up enabled.
TWELITE GOLD Implementation
AHI-compatible functions are not provided; instead, corresponding functions are implemented in SMBus.c
and SMBus.h
.
// Implementations in the TWENETcmpt library
PUBLIC void TWENET_smbus_vSMBusInit(void);
PUBLIC void TWENET_smbus_vSMBusDeInit(void);
PUBLIC void TWENET_smbus_vSMBusInit_setClk(uint32 u32clk);
PUBLIC bool_t TWENET_smbus_bSMBusWrite(uint8 u8Address,
uint8 u8Command, uint8 u8Length, uint8* pu8Data);
PUBLIC bool_t TWENET_smbus_bSMBusSequentialRead(uint8 u8Address,
uint8 u8Length, uint8* pu8Data);
// SMBus.h uses inline definitions to call the above functions
static inline void vSMBusInit(void) {
TWENET_smbus_vSMBusInit();
}
static inline void vSMBusInit_setClk(uint32 u32Clk) {
TWENET_smbus_vSMBusInit_setClk(u32Clk);
}
static inline void vSMBusDeInit() {
TWENET_smbus_vSMBusDeInit();
}
static inline void vSMBusDeInit(void) {
TWENET_smbus_vSMBusInit();
}
static inline bool_t bSMBusWrite(uint8 u8Address, uint8 u8Command,
uint8 u8Length, uint8* pu8Data) {
return TWENET_smbus_bSMBusWrite(u8Address, u8Command, u8Length, pu8Data);
}
static inline bool_t bSMBusSequentialRead(uint8 u8Address, uint8 u8Length,
uint8* pu8Data) {
return TWENET_smbus_bSMBusSequentialRead(u8Address, u8Length, pu8Data);
}
4.4.6 - AHI Functions and Explanations for SPI
SPI
This section covers the implementation of AHI-compatible functions for SPI.
- This implementation is not intended to maintain full compatibility.
- Notes and considerations known at the time of writing are described here.
- Internal implementations may change without notice.
- For parameters mentioned in the explanations, only items requiring attention are described; for omitted parts, refer to the original AHI library manual.
The following pins are used for SPI operation:
Signal | Pin Name (PIO No.) | Description |
---|---|---|
SCK | SPLCLK=DIO11(PIO0) | Clock signal This pin is shared with SPICLK and DIO11 |
MOSI | DIO18(PIO2) | SPIMOSI. Output from TWELITE side, input to external SPI device. |
MISO | SPIMISO(PIO5) | SPIMISO. Input to TWELITE side, output from external SPI device. |
SEL0 | DIO19(PIO3) | |
SEL1 | DIO0(PIO16) | |
SEL2 | DIO1(PIO17) |
When using alternate pin assignments (set via vAHI_SpiSetLocation_MW(FALSE)
):
Signal | Pin Name (PIO No.) | Description |
---|---|---|
SCK | ADC1(PIO15) | Clock signal |
MOSI | DIO1(PIO17) | SPIMOSI. Output from TWELITE side, input to external SPI device. |
MISO | DIO2(PIO18) | SPIMISO. Input to TWELITE side, output from external SPI device. |
SEL0 | DIO0(PIO16) | |
SEL1 | DIO8=ADC2(PIO14) | This pin is shared with DIO8 and ADC2 |
SEL2 | DIO12(PIO13) |
SPI operates using hardware functionality, so there may be some differences in pin behavior (especially the HIGH/LOW state when no transfer is occurring).
- The implementation uses blocking transfers. To maintain code compatibility, ensure to include polling wait code immediately after transfer API calls (
bAHI_SpiPollBusy()
,vAHI_SpiWaitBusy()
).
vAHI_SpiConfigure()
void vAHI_SpiConfigure(
uint8 u8SlaveEnable,
bool_t bLsbFirst,
bool_t bPolarity,
bool_t bPhase,
uint8 u8ClockDivider,
bool_t bInterruptEnable,
bool_t bAutoSlaveSelect);
Initializes the SPI.
bInterruptEnable
is not supported; this parameter is ignored.
vAHI_SpiDisable()
void vAHI_SpiDisable(void);
Stops the use of SPI.
vAHI_SpiSelect()
void vAHI_SpiSelect(
uint8 u8SlaveMask)
Selects the SPI SELECT pin.
- If
bAutoSlaveSelect
invAHI_SpiConfigure()
is set to TRUE, specifies the pin to control but does not control it at the time of this call. - If
bAutoSlaveSelect
invAHI_SpiConfigure()
is set to FALSE, controls the SELECT pin (sets the target pin LOW, all others HIGH).
vAHI_SpiStop()
PUBLIC void vAHI_SpiStop(void);
Deselects the SELECT pin.
Performs the same operation as vAHI_SpiSelect(0)
.
vAHI_SpiStartTransfer()
void vAHI_SpiStartTransfer(
uint8 u8CharLen,
uint32 u32Out);
void vAHI_SpiStartTransfer32(uint32 u32Out);
void vAHI_SpiStartTransfer16(uint16 u16Out);
void vAHI_SpiStartTransfer8(uint8 u8Out);
Executes an SPI transfer.
- This process runs in blocking mode.
- If the bit length is not a multiple of 8, the transfer will be split into 2–3 parts.
- When specifying 32-bit transfers, regardless of the memory byte order (endianness), data is sent from the most significant byte to the least significant byte.
As a result, the transfer waveform will be identical on both BLUE and GOLD.
AHI_SpiReadTransfer()
static inline uint32 u32AHI_SpiReadTransfer32(void);
static inline uint16 u16AHI_SpiReadTransfer16(void);
static inline uint8 u8AHI_SpiReadTransfer8(void);
Call this after the transfer completes to return the read value.
bAHI_SpiPollBusy()
bool_t bAHI_SpiPollBusy(void);
inline void vAHI_SpiWaitBusy(void) { while(bAHI_SpiPollBusy()); }
Always returns FALSE because the transfer API performs blocking transfers.
bAHI_SpiTransferBlocking_MW()
bool_t bAHI_SpiTransferBlocking_MW(
uint8 *au8tx,
uint8 *au8rx,
uint8 u8len);
Performs byte-level SPI transfers.au8tx
is the transmit data array, au8rx
is the receive data array, and u8len
is the number of bytes to transfer.
- Data is transferred sequentially from the beginning of the array.
To transfer from LSB first, store the LSB-side bytes first in the array. The same applies to the received data.
vAHI_SpiWaitBusy()
void vAHI_SpiWaitBusy(void);
Returns immediately.
vAHI_SpiSetLocation_MW()
void vAHI_SpiSetLocation_MW(bool_t bLocation);
Changes the pin assignment configuration.
If using the default pin assignments, calling this function is unnecessary.
If using the alternate pins, call this function before invoking vAHI_SpiConfigure()
.
bLocation == FALSE
(default) → Uses the default pin assignments.bLocation == TRUE
→ Uses the alternate pin assignments.
Others
Transfer Splitting
When performing transfers with vAHI_SpiStartTransfer()
that are not a multiple of 8 bits (e.g., 8, 16, 24, 32 bits),
the transfer is internally split into two parts.
As a result, the waveform will be held for a certain period between the first and second transfers.
Behavior on Wake from Sleep
If the SPI bus was initialized before entering RAM-retention sleep, the initialization state will be restored upon wake-up. For RAM-off sleep, normal DIO initialization will be performed at startup.
To improve code compatibility with BLUE/RED, explicitly call vAHI_SpiDisable()
before sleep.
4.4.7 - AHI Functions and Explanations for Random Numbers
Random (Random Numbers)
Implementation of AHI-compatible functions related to random number generation.
- This implementation is not intended to maintain full compatibility.
- Notes and considerations known at the time of writing are described here.
- Internal implementations may change without notice.
- For parameters mentioned in the explanations, only items requiring attention are described; for omitted parts, refer to the original AHI library manual.
vAHI_Start|StopRandomNumberGenerator()
void vAHI_StartRandomNumberGenerator(bool_t const bMode, bool_t const bIntEn);
void vAHI_StopRandomNumberGenerator(void);
Starts or stops random number generation.
u16AHI_ReadRandomNumber()
uint16 u16AHI_ReadRandomNumber(void);
Reads a 16-bit random value.
- If random number generation has not been started, returns
57005
.
u32AHI_ReadRandomNumber_MW()
uint32 u32AHI_ReadRandomNumber_MW(void);
(TWELITE GOLD only) Reads a 32-bit random value.
- If random number generation has not been started, returns
3735928559
.
vAHI_ReinitRandomNumberGenerator_MW()
void vAHI_ReinitRandomNumberGenerator_MW();
(TWELITE GOLD only) Reinitializes the random number generator device.
4.4.8 - AHI Functions and Explanations for UART
UART
UART usage relies on serial.c
, .h
and uart.c
, .h
found in TWENETutils.
This section explains AHI-compatible functions with behaviors specific to TWELITE GOLD.
- When using UART1, you must call
vAHI_UartSetLocation()
orvAHI_UartSetLocationByPio_MW()
to specify the assigned ports beforehand. - UART0 does not require any special procedure like UART1 for usage.
vAHI_UartSetLocation()
void vAHI_UartSetLocation(uint8_t u8port, bool_t bSel);
Specifies the port assignment for UART.
- Does not affect UART0 assignment; it cannot be changed from the default ports (DIO6,7).
- Two assignment options are available for UART1.
- This function must be called when using UART1.
- To assign other options for UART1, use
vAHI_UartSetLocationEx_MW()
.
bSel | TX | RX |
---|---|---|
FALSE | DIO14(PIO10) | DIO15(PIO11) |
TRUE | DIO11(PIO0)*1 | DIO13(PIO1) |
*1 This overlaps with the default SPICLK pin.
vAHI_UartSetLocationByPio_MW()
void vAHI_UartSetLocationByPio_MW(uint8_t u8port, uint8 u8TxPort, uint8 u8RxPort)
Assigns ports for UART.
Specify E_AHI_UART_1
for u8port
.
Set the PIO numbers for the TX and RX ports using u8TxPort
and u8RxPort
.
Available PIO numbers (DIO numbers):
- TX: 0 (DO0, DIO11), 6 (DIO5), 10 (DIO14), 20 (DIO16)
- RX: 7 (DIO4), 1 (DIO13), 11 (DIO15), 19 (DIO13)
vAHI_UartDisable()
void vAHI_UartDisable(uint8_t u8port)
Disables the UART port specified by u8port
.
The pin state will return to its initial configuration as defined in TWENETmcu/board/pin_mux.c
at startup.
4.4.9 - AHI Functions and Explanations for WatchDog (WDT)
WatchDog(WDT)
vAHI_WatchdogStart()
void vAHI_WatchdogStart(uint8 u8Prescale);
Starts the Watchdog Timer (WDT).
- The timeout period is set approximately. Specifically, when
u8Prescale == 0
, the timeout is8 ms
; otherwise, it is set as((1UL << (u8Prescale - 1)) + 1) * 8 ms
, passed tothe_wwdt->init()
. - If a value outside the valid range (
u8Prescale > 12
) is specified,u8Prescale = 10
(about 4 seconds) will be used. - When compiled with
-DDEBUG
, this process is skipped, and the WDT remains stopped.
vAHI_WatchdogStop()
void vAHI_WatchdogStop();
On TWELITE GOLD, once started, the watchdog cannot be stopped.
This function is called when changing the watchdog timer’s timeout period, as shown below:
...
vAHI_WatchdogStop(); // Calls the stop API (actually does not stop)
vAHI_WatchdogStart(12); // Reconfigures to approximately 16 seconds
vAHI_WatchdogRestart()
void vAHI_WatchdogRestart();
Call this before the watchdog timer times out.
- When compiled with
-DDEBUG
, this process is skipped.
4.4.10 - AHI Functions and Explanations for WakeTimer
WakeTimer
Implementation of vAHI_WakeTimer
-related compatible functions.
- This implementation is not intended to maintain full compatibility.
- Notes and considerations known at the time of writing are provided.
- The internal implementation may change without notice.
- Only parameters requiring attention are documented; for others, refer to the original AHI library manual.
The Wake Timer has two channels, both running continuously regardless of sleep state.
The counter operates in a decrementing manner, generating an interrupt when it reaches zero.
Additionally, since the wake timer keeps running, it can be used as a clock to measure elapsed time since startup.
For this purpose, a set of FRWT (Free Running WTimer) functions is also provided.
- Timer width:
E_AHI_WAKE_TIMER_0
= 41-bit,E_AHI_WAKE_TIMER_1
= 28-bit.
The latter differs from BLUE/RED (JN516x); note that the maximum count value is0x0FFFFFFF
when calculating time differences.
For example, to compute elapsed counts betweenct1
andct2
, use(((ct2 << 4) - (ct1 << 4)) >> 4)
. - This library does not provide functions handling timer values exceeding 32 bits.
- In the mwx library and some applications, one timer (
E_AHI_WAKE_TIMER_0
) is used continuously for time measurement through the Free Running WTimer (FRWT
) API.
vAHI_WakeTimerEnable()
void vAHI_WakeTimerEnable(uint8 u8Timer,
bool_t bIntEnable)
Initializes the timer.
vAHI_WakeTimerStart()
void vAHI_WakeTimerStart(uint8 u8Timer, uint32 u32Count)
Starts the timer.u32Count
specifies the counter value.
For TWELITE GOLD, to trigger an interrupt after 1 second, specify 32768
(the frequency of the 32KHz crystal oscillator).
vAHI_WakeTimerStop()
void vAHI_WakeTimerStop(uint8 u8Timer)
Stops the timer.
u32AHI_WakeTimerCalibrate()
uint32 u32AHI_WakeTimerCalibrate(void);
Returns the wake timer calibration value 10000
.
- Normally, with a low-precision RC timer, this value would vary by about ±30%, but since TWELITE GOLD uses a 32KHz crystal-based timer circuit, this calibration is unnecessary, and the function always returns
10000
.
u32AHI_WakeTimerRead()
uint32 u32AHI_WakeTimerRead(uint8 dev)
Returns the counter value. The wake-up interrupt occurs when the counter reaches zero. Afterward, the counter continues decrementing (after 0, it rolls over to the maximum value).
u8AHI_WakeTimerStatus()
uint8 u8AHI_WakeTimerStatus(void)
Returns the bitmap indicating the timer status.E_AHI_WAKE_TIMER_0
→ E_AHI_WAKE_TIMER_MASK_0
(1)
E_AHI_WAKE_TIMER_1
→ E_AHI_WAKE_TIMER_MASK_1
(2)
u8AHI_WakeTimerFiredStatus()
uint8 u8AHI_WakeTimerFiredStatus()
Used immediately after wake-up.
If the wake-up source is WTIMER, a non-zero value is returned.
- For
E_AHI_WAKE_TIMER_0
, returnsE_AHI_WAKE_TIMER_MASK_0
(1)
. - For
E_AHI_WAKE_TIMER_1
, returnsE_AHI_WAKE_TIMER_MASK_1
(2)
.
Free Running WTimer (FRWT)
Uses one channel of the WAKE TIMER (typically E_AHI_WAKE_TIMER_0
)
as a continuously running real-time counter.
This allows time measurement regardless of the sleep state.
Global Variables
G_TWENET_FREE_RUNNING_WTIMER_ENABLED()
uint8_t G_TWENET_FREE_RUNNING_WTIMER_ENABLED() // MACRO
This variable is set in the cbAppColdStart(FALSE)
call.
Specify 0x80
to operate E_AHI_WAKE_TIMER_0
as FRWT.
While the WAKE TIMER counter decrements over time, FRWT increments.
- In the mwx library, FRWT with
E_AHI_WAKE_TIMER_0
is automatically configured.
g_twenet_free_running_wtimer_boot_tick
uint32_t g_twenet_free_running_wtimer_boot_tick
Stores the counter value immediately after waking from sleep (with RAM retention).
This is set when vAHI_FRWTSetBootCount_MW()
is called from within the TWENET library.
vAHI_FRWTStart_MW()
void vAHI_FRWTStart_MW(uint8_t u8Timer)
This function is primarily used within the TWENET library and
should not be used in user programs.
FRWT is started based on the setting of the global variable G_TWENET_FREE_RUNNING_WTIMER_ENABLED()
.
u32AHI_FRWTGetCurrentCount_MW()
uint32 u32AHI_FRWTGetCurrentCount_MW()
Returns the FRWT counter value (32000 counts/second).
u32AHI_FRWTGetCurrentCount_msec_MW()
uint32 u32AHI_FRWTGetCurrentCount_msec_MW(uint32* dec_part)
Returns the current FRWT count in milliseconds.
dec_part
specifies eitherNULL
or a pointer to auint32
variable.
If provided, it returns the value in 1/10 millisecond units (0..9).
u32AHI_FRWTConvertCount_msec_MW()
static inline uint32 u32AHI_FRWTConvertCount_msec_MW(uint32 ct, uint32* dec_part) {
// note: see wtimer::freerun_ct_convert_msec()
uint64_t v = 1000ull * ct;
if(dec_part) *dec_part = (10*(v & 32767)) >> 15;
return (uint32)(v >> 15);
}
Converts the FRWT counter value to milliseconds.
If dec_part
is specified, it returns the value in 1/10 millisecond units (0..9).
i32AHI_FRWTCompareCount_MW()
int32 i32AHI_FRWTCompareCount_MW(uint32 val_past, uint32 val_now)
Compares FRWT counter values.
Specify val_now
as the more recent value and val_past
as the older value.
In this case, the function returns a positive count value.
i32AHI_FRWTCompareCount_msec_MW()
int32 i32AHI_FRWTCompareCount_msec_MW(uint32 val_past, uint32 val_now)
Compares FRWT counter values.
Specify val_now
as the more recent value and val_past
as the older value.
In this case, the function returns the positive value in milliseconds.
vAHI_FRWTSetBootCount_MW()
void vAHI_FRWTSetBootCount_MW()
This function is primarily used within the TWENET library and should not be used in user programs.
It is used to save the FRWT counter value when waking up from sleep (with RAM retention, warm boot).
uint32 u32AHI_FRWTGetBootCount_MW()
uint32 u32AHI_FRWTGetBootCount_MW()
Returns the FRWT counter value when waking up from sleep (with RAM retention, warm boot).
u32AHI_FRWTGetBootCount_msec_MW()
uint32 u32AHI_FRWTGetBootCount_msec_MW()
Converts and returns the FRWT counter value in milliseconds when waking up from sleep (with RAM retention, warm boot).
4.4.11 - AHI Functions and Explanations for Onchip Temp Sensor
Onchip Temp Sensor
In TWELITE GOLD, a temperature sensor is implemented inside the chip.
The sensor value is used as a parameter for initializing the wireless MAC layer.
Handling of Temperature Sensor During MAC Layer Initialization
- If the temperature sensor value cannot be obtained, initialization is performed with a default value of 20°C.
- If more than
G_TWENET_CHIPSENSOR_ADC_INTERVAL_MS()
milliseconds have elapsed when waking up from sleep (RAM retained), the temperature is measured again at wake-up, and the MAC layer is reinitialized based on the sensor value.
Global Variables
uint8 G_TWENET_CHIPSENSOR_AUTO_ON_BOOT()
// Macro for variable access
A configuration variable to automatically acquire the temperature sensor value. Set it in cbAppColdStart(FALSE)
.
Setting | Description | Notes |
---|---|---|
0 | Do not automatically acquire the temperature sensor value. | MAC layer temperature correction uses a fixed value (20°C). |
1 | Automatically acquire the temperature sensor value. |
uint8_t G_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
// Macro for variable access
Setting | ADC Count |
---|---|
0 | 1 |
1 | 2 |
2 | 4 |
3 | 8 |
Specifies the scaler value corresponding to the number of ADC measurements for the temperature sensor.
int32 G_TWENET_CHIPSENSOR_TEMP128TH()
// Macro for variable access
Stores the temperature measured by the chip sensor in the TWENET library (value in °C multiplied by 128).
int16 g_twenet_chipsensor_volt_on_boot;
TWENET library stores the measured voltage value [mV].
This value is recorded at the same time as the temperature sensor measurement.
uint32 G_TWENET_CHIPSENSOR_ADC_INTERVAL_MS()
= (10*60*1000ul)
// Macro for variable access
If the time elapsed since the last measurement is within the period specified by this variable, the temperature sensor reading will be skipped.
Set this in cbAppColdStart(FALSE)
.
uint8 g_twemet_chipsensor_capture_this_time;
An internal flag that determines whether to perform a temperature measurement at boot.
bAHI_AdcTemp_Measure_MW()
bool_t bAHI_AdcTemp_Measure_MW(
int32 *i32temp_128th,
int16 *i16volt_mv,
uint8 adc_times_scaler,
bool_t bTurnOnSensor)
Performs the temperature sensor measurement.
i32temp_128th
is a pointer to anint32
variable that stores the temperature measurement result.i16volt_mv
is the power supply voltage [mV] measured at the same time.adc_times_scaler
specifies the scaler value corresponding to the number of ADC measurements for the temperature sensor. For configuration values, refer to the explanation ofG_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
.- If
bTurnOnSensor
is set toTRUE
, the function powers on the temperature sensor and performs the required waiting process. If set toFALSE
, you must callvAHI_AdcTemp_TurnOn_MW()
beforehand and ensure the required wait time has passed.
vAHI_AdcTemp_TurnOn_MW()
void vAHI_AdcTemp_TurnOn_MW()
Powers on the temperature sensor. A waiting time of 100 μs is required after this call.
uint32 u32AHI_AdcTemp_GetCaptTick_MW()
uint32 u32AHI_AdcTemp_GetCaptTick_MW()
Returns the FRWT timestamp of the last temperature sensor measurement in 32KHz count units.
uint32 u32AHI_AdcTemp_GetCaptTick_msec_MW()
uint32 u32AHI_AdcTemp_GetCaptTick_msec_MW()
Returns the FRWT timestamp of the last temperature sensor measurement in milliseconds.
u32AHI_AdcTemp_ElapsedFromCapt_msec_MW(), u32AHI_AdcTemp_TickrefFromCapt_msec_MW()
uint32 u32AHI_AdcTemp_ElapsedFromCapt_msec_MW()
uint32 u32AHI_AdcTemp_TickrefFromCapt_msec_MW(uint32 tick_ref)
Returns the elapsed time in milliseconds since the last temperature measurement.
4.5 - TWENETeastl - EASTL Library
TWENETeastl - EASTL Library
EASTL is a standard template library (containers and algorithms) maintained by Electronic Arts. It is implemented following C++ STL (Standard Template Library) but was developed with the constraints of game console environments in mind, providing containers and algorithms designed for systems with strict memory usage limitations.
This library enables the use of EASTL within TWENET.
Key features include:
Fixed-memory containers (
fixed_
):
Containers with a fixed number of elements that do not perform dynamic allocation. If declared globally, memory is allocated at compile time; if declared locally, memory is allocated on the stack and available within that scope.Intrusive containers:
Unlike normal containers that can store arbitrary data structures, intrusive containers require inheriting a base class to maintain link information within the data structure itself.
While this restricts container usage to specific data structures, it greatly improves memory efficiency for lists or maps.
(Reference: Intrusive and non-intrusive containers)
The 2007 article EASTL (open-std.org) describes the motivation behind its development.
(Additional articles: EASTL and Game Development, Part 1, Part 2)
EASTL Library Documentation
Please refer to the HTML files under the doc
directory.
The README.md
and CONTRIBUTING.md
files, originally located in the root directory of the distribution,
have been moved to the doc/
directory.
Usage in TWENET
Please note the following:
We have not conducted comprehensive testing of the library’s operation.
Customers are responsible for verifying its functionality.
We also cannot provide support for questions regarding the usage of EASTL.
Please refer to the official documentation, source code, and related materials provided by the original authors.
- The version used is EASTL 3.07 (2018/1/31),
which is the last version compatible 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 under
test/source
has not been ported. - For sprintf related functionality, only
EA::StdC::Vsnprintf(char8_t*, ...)
is supported by callingvsnprintf_()
in theprintf.h
library.
Integration and Compilation
EASTL can be used when writing Acts.
The necessary include paths and library additions for the TWELITE development environment are already provided.
Simply include the required library headers in the code you create.
#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() {
;
}
Detailed Integration Steps
- Compile the code under
EASTL/source
into a library archive (libEASTL.a
).
Linking against this library is required during the build process. - Add the following include paths during compilation.
If $(PATH_EASTL)
points to 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 Guidelines
std::
vs eastl::
Both the standard library (std::
) and EASTL (eastl::
) define components with the same names and functionalities.
While they may sometimes be interoperable, using them together can lead to compilation errors.
As a general rule, when working with EASTL, use definitions provided by EASTL itself.
For example, attempting to store an eastl::fixed_string
in a std::unique_ptr
will result in a compiler error.
Global Object Initialization 1 (Placement New)
In TWENET development, due to compiler constraints, constructors for globally declared objects are not executed.
Memory for such globally declared objects is only zero-initialized.
If the code is executed as-is, it will typically hang due to null pointer access.
To properly initialize these 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();
}
Since the placement new code can look a bit messy, 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: Arguments from the second one onward are variadic and passed directly to the constructor.
Global Object Initialization 2 (unique_ptr)
As another way to initialize global objects, you can use unique_ptr
(std::unique_ptr reference).
Both std::
and eastl::
provide unique_ptr
, but for EASTL classes, you should use the one from eastl::
.
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 example shows an element definition 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 of intrusive_list
must inherit from the intrusive_list_node
base class. The base class contains link pointers used to maintain the list. Here we also define comparison operators used by functions such as sort
.
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 strucure
// 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 that the library bundled with TWENET targets EASTL 3.07 and may not include elements implemented or changed afterward.
- cpprefjp - C++ Japanese Reference — A C++ reference; its STL explanations are particularly helpful.
About this sample
The EASTL license description 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.
*/
The sample code applies MWSLA-1J/E.
4.6 - TWENETstgs - twesettings Library
TWENETstgs - twesettings Library
This library primarily contains various functions for performing configuration processing in interactive mode.
Note: These functions are not publicly exposed as APIs for end-users.
4.6.1 - printf library
printf-equivalent functions
{{< hint color=“info” >}}
The printf
library to reference is stored in TWENETmcu/printf
.
{{< /hint >}}
This TWENETstgs
defines fprintf
, vfprintf
, and sprintf
equivalent functions using an open-source printf
library.
int TWE_fprintf(TWE_tsFILE *fp, const char *format, ...);
int TWE_vfprintf(TWE_tsFILE *fp, const char *format, va_list va);
#define TWE_snprintf(out,siz,fmt,...) snprintf_(out,siz,fmt,__VA_ARGS__)
Referenced Source Code Description
///////////////////////////////////////////////////////////////////////////////
// \author (c) Marco Paland (info@paland.com)
// 2014-2019, PALANDesign Hannover, Germany
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
// embedded systems with a very limited resources.
// Use this instead of bloated standard/newlib printf.
// These routines are thread safe and reentrant.
//
///////////////////////////////////////////////////////////////////////////////
4.6.2 - TWESTG_CMD_u32CmdOp() Command Explanation
TWESTG_CMD_u32CmdOp()
.TWESTG_CMD_u32CmdOp() Command Explanation (for Internal Developers)
TWESTG_CMD_u32CmdOp()
function provides common procedures with applications (firmware) implemented using the TWENETstgs library. However, this information relates to the internal implementation of the library and is not intended for use by general users.Overview
The TWESTG_CMD_u32CmdOp()
function in twesettings_cmd.[ch]
is intended to execute 0xdb
commands. This function includes processes such as obtaining module various information, obtaining configuration information, reflecting configuration information, and resetting. Many processes call the configuration-related helper function TWEINTRCT_cbu32GenericHandler()
.
Data Types
TWE_APIRET
: Success if the0x80000000
bit is set, failure if not. The remaining 31 bits are used for parameters.TWE_tsBuffer
: A structure containing a pointer to the buffer, the sequence length, and the maximum buffer length.TWESTG_tsFinal
: The management structure for configuration-related settings.
TWESTG_CMD_u32CmdOp()
TWE_APIRET TWESTG_CMD_u32CmdOp(uint8 u8Op, TWE_tsBuffer *pBufIn, TWE_tsBuffer *pBufOut, TWESTG_tsFinal *psFinal)
Performs processing corresponding to u8Op
. Input data pBufIn
and output data pBufOut
are used depending on the process. The last parameter specifies the configuration management structure psFinal
.
Parameter | Type | Description |
---|---|---|
u8Op | uint8 | Specifies the processing content. |
pBufIn | TWE_tsBuffer * | Input sequence. |
pBufOut | TWE_tsBuffer * | Specifies the storage area for output data. NULL can be specified for some processes. The state on processing failure is undefined in principle. |
psFinal | TWESTG_tsFinal * | Specifies the configuration information management structure. |
The u8Op
overview is as follows:
E_TWESTG_CMD_OP_ACK = 0xF0 ACK processing
E_TWESTG_CMD_OP_QUERY_MODULE_INFO = 0xF1 Acquisition of SID, etc.
E_TWESTG_CMD_OP_APPLY_SETTINGS = 0xF2 Apply settings (do not save)
E_TWESTG_CMD_OP_QUERY_SETTINGS = 0xF3 Read settings
E_TWESTG_CMD_OP_MODULE_CONTROL = 0xF8 Various processes related to settings
E_TWESTG_CMD_OP_REVERT = 0xFD Revert settings
E_TWESTG_CMD_OP_SAVE = 0xFE Save settings
E_TWESTG_CMD_OP_DO_MDDULE_RESET = 0xFF, Module reset
The return value indicates success or failure. Parameters may be set depending on the process.
Return Value | Value | Status |
---|---|---|
TWE_APIRET_SUCCESS | b0..b7 → u8Op, others depend on processing | On success |
TWE_APIRET_FAIL | b0..b7 → u8Op, others depend on processing | On failure |
Processing
E_TWESTG_CMD_OP_ACK (F0)
Performs an ACK response. The input sequence is output as-is.
Example
(None) -> 01 : If no input, 01 is returned.
112233 -> 112233 : If 112233, it is returned as-is in the output.
E_TWESTG_CMD_OP_QUERY_MODULE_INFO (F1)
Retrieves various module information.
Input Column | Data Type | Value | Content |
---|---|---|---|
[0] | OCTET | 0x01 | Get module’s SID. |
Other | Undefined | ||
Subsequent data is undefined |
Output Column ([0] == 0x01) | Data Type | Value | Content |
---|---|---|---|
[0..3] | BE_DWORD | Module’s SID. |
E_TWESTG_CMD_OP_APPLY_SETTINGS(F2)
Modifies configuration information.
- Configuration information will not be applied until it is saved and the module is reset.
- The behavior of the application in an unapplied state is undefined.
- If you transition to interactive mode in an undefined state, the changed data will be discarded.
- Even when attempting to change to the same content as existing data, this process returns a successful return value. However, if a save (
E_TWESTG_CMD_OP_SAVE
) is executed, no actual save will occur. - This process does not write to the output (
pBufOut
).
Input Column | Data Type | Value | Content |
---|---|---|---|
[0] | OCTET | 0x01 | Change the setting specified by ID. |
[1] | OCTET | Not 0x00 | Setting ID |
[2..] | Data type dependent |
Configuration Data
Setting ID | Content | Input Data | Remarks |
---|---|---|---|
0x01 | Application ID | BE_DWORD (uint32_t) | |
0x02 | Logical ID (8bit) | OCTET (uint8_t) | |
0x03 | Channel | OCTET (uint8_t) | |
0x04 | Multiple Channels | BE_WORD(uint16_t) | b0: ch11, b1: ch12, …, b15: ch16 |
BE_DWORD(uint32_t) | Bitwise OR of 1UL << ch (e.g., for 11, 13 it’s `1UL « 11 | ||
0x05 | Radio Output and Retransmission | OCTET (uint8_t) | Upper 4 bits: retransmission count, Lower 4 bits: output setting (0..3, 3 is highest output) |
0x06, 0x08, 0x09, 0x0A | Option (32bit) | BE_DWORD (uint32_t) | |
0x07 | UART Settings | BE_WORD (int16_t) | Input configuration data in internal format as-is. |
BE_DWORD | Specifies baud rate (9600 … 250000). Other communication conditions are 8N1. | ||
BE_DWORD OCTET OCTET OCTET | Specifies all parameters: - Baud rate (DWORD) - Data bits (7 or 8) - Parity (‘N’ or ‘E’ or ‘O’) - Stop bits (1 or 2) |
Example
01011234BEEF Sets Application ID (0x01) to 0x1234BEEF.
010212 Sets Channel (0x02) to 0x12 (18).
E_TWESTG_CMD_OP_QUERY_SETTINGS(F3)
Retrieves configuration information.
Input Column | Data Type | Value | Content |
---|---|---|---|
[0] | OCTET | 0x01 | (QTYP) Get the setting specified by ID. |
[1] | OCTET | Not 0x00 | Setting ID |
Output for QTYP==1
Remarks | ||
---|---|---|
[0] | OCTET | Data type (uint8_t: 1, int8_t: 2, uint16_t: 3, int16_t: 4, uint32_t: 5, int32_t: 6, uint8_t[]: 0x80 (lower 5 bits are data length)) |
[...] | Data type dependent (Integer types WORD, DWORD are Big Endian order) |
Setting ID | Content | Input Data | Remarks |
---|---|---|---|
0x01 | Application ID | BE_DWORD (uint32_t) | |
0x02 | Logical ID (8bit) | OCTET (uint8_t) | |
0x03 | Channel | OCTET (uint8_t) | |
0x04 | Multiple Channels | BE_WORD(uint16_t) | b0: ch11, b1: ch12, …, b15: ch16 |
0x05 | Radio Output and Retransmission | OCTET (uint8_t) | Upper 4 bits: retransmission count, Lower 4 bits: output setting (0..3, 3 is highest output) |
0x06, 0x08, 0x09, 0x0A | Option (32bit) | BE_DWORD (uint32_t) | |
0x07 | UART Settings | BE_WORD (int16_t) | Internal format configuration data. b15: 1 for 7bit, 0 for 8bit. b14: 1 for STOPBIT=2, 0 for 1. b12,13: 0->NONE, 1->ODD, 2->EVEN. b0..b11->Baud rate / 100. |
Example
0101 -> 051234BEEF -> Application ID (uint32_t 0x1234beef)
0102 -> 010D -> Channel (uint8_t 13)
E_TWESTG_CMD_OP_REVERT (0xFD)
By executing E_TWESTG_CMD_OP_SAVE
immediately after this command, the configuration information is reverted to its initial values.
- Calls
TWEINTRCT_cbu32GenericHandler(psIntr, E_TWEINRCT_OP_REVERT, TRUE, 0, NULL)
. TheTRUE
specified in the third argument means that the saved configuration information is not loaded. Ensure that the application’sTWEINTRCT_cbu32GenericHandler()
is correctly implemented.
No input data, no output data.
E_TWESTG_CMD_OP_SAVE (0xFE)
When configuration information is changed, it is saved to non-volatile memory.
- If attempting to overwrite or change to the same values that are already set, no save is performed. The function returns
TWE_APIRET_SUCCESS_W_VALUE(0x100 | E_TWESTG_CMD_OP_SAVE)
. - If a save is performed, a reset should be carried out promptly (operation with changed settings without reset is undefined).
No input data, no output data.
E_TWESTG_CMD_OP_DO_MDDULE_RESET (0xFF)
Resets the module.
No input data, no output data.