This is the multi-page printable view of this section. Click here to print...

Return to the regular view of this page

As of 2025-09-22

API Reference

API reference for TWELITE-related software is here.

1 - MWX Library

A C++ library for developing act
MWX Library is a C++ library for developing act.

1.1 - MWX Library

Latest version

1.1.1 - General

About the MWX Library
The MWX Library is designed to make programming for TWELITE modules easier and more extensible. Based on the TWENET C Library previously used in MWSDK, the MWX Library serves as the application development layer.
+-----------------------+
|   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.

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 and new[] 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()) like new ((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.

1.1.1.1 - License

Warranty and 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

Terminology Guide
This document explains terminology used throughout this guide.

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).

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.

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 information
This section describes the C++ language usage within the MWX library, including specifications, known limitations, notes, and design memos.

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 and new[] 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 like new ((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 NameDescription
smplbufAn 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.
smplqueImplements 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 NameDescription
alloc_attachSpecifies 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_staticAllocates as a static array within the class. Use when the size is known in advance or for temporary use.
alloc_heapAllocates 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.

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 typedefs 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.

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

Definitions commonly included throughout the library

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

Objects defined for operating networks and peripherals

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

Core class for TWENET usage (mwx::twenet)
The 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

<< 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

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.

ParameterDescription
u32PeriodmsSleep duration [ms]
bPeriodicRecalculates 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.
bRamoffIf set to true, sleep without retaining RAM (after waking up, reinitialization should start from setup() instead of wakeup())
u8DeviceSpecifies the wake-up timer used for sleep. Specify either TWENET::SLEEP_WAKETIMER_PRIMARY or TWENET::SLEEP_WAKETIMER_SECONDARY.

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 by network (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.

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.

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.

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

ADC (mwx::periph_analogue.hpp)
Analogue performs ADC execution and value acquisition. Multiple channels can be continuously acquired at once, and this can be sequentially executed according to the cycle of a timer or other periodic event.

Constants

Pin Definitions

ConstantTypeStandard App Pin Name
uint8_t PIN_ANALOGUE::A1 = 0ADC1 PinAI1
uint8_t PIN_ANALOGUE::A2 = 1ADC2 PinAI3
uint8_t PIN_ANALOGUE::A3 = 2``uint8_t PIN_ANALOGUE::D0 = 2ADC3 Pin (DIO0) *1AI2
uint8_t PIN_ANALOGUE::A4 = 3``uint8_t PIN_ANALOGUE::D1 = 3ADC4 Pin (DIO1) *1AI4
uint8_t PIN_ANALOGUE::VCC = 4Vcc Power Supply Voltage

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.

ParameterDescription
bWaitInitIf true, waits for the internal semiconductor regulator initialization.
kick_evSpecifies 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_finishCallback 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).

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.

1.1.3.3 - Buttons

Digital Input Management Class (mwx::periph_buttons)
Detects changes in digital input. This class detects changes when the same detected value is obtained multiple times. It is effective in reducing the effects of mechanical button chatter.

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

Perform read and write operations on the built-in 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

Pulse Counter (mwx::periph_pulse_counter)
The pulse counter is a circuit that counts pulses even when the microcontroller’s CPU is not operating.

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.

SettingConsecutive SamplesMax Detection Frequency
0-100kHz
123.7kHz
242.2kHz
381.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

UART0 port (mwx::serial_jen)
Implements 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 from setup() in user code.
  • The Serial1 object is provided within the library but is not initialized. To enable UART1, perform the necessary initialization procedures Serial1.setup(), Serial1.begin().

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
ParameterDescription
buf_txFIFO buffer size for TX
buf_rxFIFO buffer size for RX

begin()

void begin(unsigned long speed = 115200, uint8_t config = 0x06)

Initializes the hardware.

ParameterDescription
speedSpecifies the UART baud rate
configWhen 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).

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.

1.1.3.7 - SerialParser

Formatted input for serial port (mwx::serial_parser)
This built-in class is defined as an embedded object intended for use in formatted input via the serial port.

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

Performs reading and writing on the SPI bus (controller side).
Performs reading and writing on the SPI bus (controller side).

Notes

Constants

ConstantMeaning
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.

ParameterDescription
slave_selectSpecifies the select pin of the target peripheral.
0 : DIO19``1 : DIO0 (DIO19 is reserved)``2 : DIO1 (DIO0,19 are reserved)
settingsSpecifies 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.

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)

SPI (Method-based usage)
After initializing the hardware with the 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)

SPI (How to use with helper class)
The helper class version is a more abstract implementation. By creating a read/write object 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.

  1. The x object is created inside the if(...). At the same time, the SPI bus select pin is set. (The type is resolved by universal reference auto&& with type inference.)
  2. The created x object defines operator bool () which is used for evaluation in the conditional expression. For SPI bus, it always evaluates to true.
  3. The x object defines the method uint8_t transfer(uint8_t), which performs an 8-bit read/write transfer to SPI when called.
  4. At the end of the if() { ... } scope, the destructor of x 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

System Timer (mwx::periph_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.

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

Timer, PWM (mwx::periph_timer)
Timers have two functions: generating software interrupts at specified intervals and producing PWM output at specified intervals. The TWELITE wireless module provides five timers, from 0 to 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.

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.

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

Read/write as 2-wire serial (I2C) master (controller) (mwx::periph_wire)
Performs read/write operations as a 2-wire serial (I2C) master (controller).

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

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.

ParameterDescription
u8modeSpecifies 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_portaltChanges 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.

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)

Wire (using member functions)

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.

ParameterDescription
u8addressI2C address to read from
lengthNumber of bytes to read
b_send_stop=trueIf true, a STOP bit is issued at the end of reading
Return type size_typeNumber 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.

ParameterDescription
u8addressI2C address to write to

write(value)

size_type write(const value_type value)

Writes a single byte.

ParameterDescription
valueByte to write
Return size_typeNumber 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.

ParameterDescription
*valueByte sequence to write
size_typeNumber of bytes
Return size_typeNumber of bytes written. 0 indicates an error.

endTransmission()

uint8_t endTransmission(bool sendStop = true)

Finalizes the write operation.

ParameterDescription
sendStop = trueIssues a STOP bit
Return uint8_t0: success, 4: failure

1.1.3.11.2 - Wire (Helper Class Version)

Wire (How to use with helper classes)
The helper class version is a more abstract implementation. Generating objects 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.

  1. The rdr object is created inside if(...). (The type is resolved as a universal reference auto&& by type inference.)
  2. The created rdr object defines operator bool () and is used for evaluation in the condition. If communication is possible with the specified ID, it returns true.
  3. The rdr object defines int 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.
  4. The destructor of rdr is called at the end of the if() { ... } scope, issuing a STOP 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.

ParameterDescription
addrI2C address for reading
read_countNumber 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.

  1. The wrt object is created inside if(...). (The type is resolved as auto to avoid long type names.)
  2. The created wrt object defines operator bool () and is used for evaluation in the condition. If communication is possible with the specified ID, it returns true.
  3. The wrt object defines int 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.
  4. The destructor of wrt is called at the end of the if() { ... } scope, issuing a STOP on the two-wire serial bus.

get_writer()

periph_wire::writer
get_writer(uint8_t addr)

Obtains a worker object used for I2C writing.

ParameterDescription
addrI2C 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

Various Classes

1.1.4.1 - MWX_APIRET

Return Value Class
API return value class wrapping a 32-bit type. The MSB (bit 31) indicates success or failure. Bits 0 to 30 are used to store the return value.
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

Memory Allocation
Used as a template argument for container classes (smplbuf, smplque) to specify or allocate internal memory regions.
Class NameDescription
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

Container class for accelerometer data
A struct for storing three-axis accelerometer sensor values, with additional utilities to enhance data handling convenience.
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

Received Packet
This class is a wrapper for the 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.

Methods

get_payload()

smplbuf_u8_attach& get_payload()

Retrieves the data payload of the packet.

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).

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.

ValueDescription
The serial number is used as the destination.Specifies the serial number as the destination.
0x00-0xFFAn 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.

ValueDescription
mwx::NETWORK::LAYEREDPacket from <NWK_LAYERED>
mwx::NETWORK::SIMPLEPacket from <NWK_SIMPLE>
mwx::NETWORK::NONEPacket not transmitted via a network (e.g., App_Twelite)
OtherError or unidentified packet

1.1.4.5 - packet_tx

Transmission Packet
This class is a wrapper for the 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 to 0xEF indicates an 8-bit logical ID. 0xFE is broadcast to child nodes (0x010xEF), and 0xFF 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 packet u8count+1 times. The force_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.

  • <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, use tx_addr(0xFF) for general broadcast or tx_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

Serial Format Input/Output (mwx::serial_parser)
Used for serial format input and output. It has an internal buffer that holds a parsed binary sequence. During input, it reads a sequence one byte at a time and stores it in the internal buffer according to the specified format, completing the process when the entire sequence has been interpreted. For output, it outputs the buffer according to the specified output format.

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.

ConstantFormat Type
uint8_t PARSER::ASCII = 1ASCII format
uint8_t PARSER::BINARY = 2Binary 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

SectionByte Count (Original)Byte Count (Format)Description
Header1: (0x3A) colon character
DataN2NEach byte is represented as two ASCII characters (A–F in uppercase). For example, 0x1F is represented as 1 (0x31) and F (0x46).
Checksum2The 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.
Footer2[CR] (0x0D) and [LF] (0x0A) characters

Binary Format

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

SectionByte Count (Original)Byte Count (Format)Description
Header2Use 0xA5 0x5A
Data Length2Two bytes in big-endian format with MSB (0x8000) set. For example, if the data length is 8 bytes, use 0x80 0x08.
DataNNSpecifies the original data
Checksum1XOR 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_attachUse an existing buffer specified via begin()
serparser_local<N>Allocate an internal buffer of N bytes
serparser_heapAllocate 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.

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

Packet Parser
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

Packet Type Definitions

The following packet types are supported:

NameDescription
PKT_ERRORUsed before parsing or when the packet type cannot be determined. The TwePacket does not contain valid data.
PKT_TWELITEParsed result of the 0x81 command from the standard application App_Twelite.
PKT_PALParsed format of TWELITE PAL serial output.
PKT_APPIOParsed UART messages from the remote control application App_IO.
PKT_APPUARTParsed extended format from the serial communication application App_UART.
PKT_APPTAGParsed UART messages from the wireless tag application App_Tag. Sensor-specific parts are not interpreted but returned as raw payload bytes.
PKT_ACT_STDOutput format used by samples of Act.

1.1.4.7.2 - identify_packet_type()

Determine 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

Packet Type
This is the base class for packet types. The 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;
};

1.1.4.7.3.1 - TwePacketTwelite

Packet from App_Twelite
The 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

Packet from App_IO
The 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

Packet from App_UART
The 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.

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

Packet from App_PAL
The 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

Container class with array structure
This is a container class based on an internal array structure. The maximum buffer size is defined at initialization, and within this range it behaves as a variable-length array.
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().

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.

1.1.4.8.1 - get_stream_helper()

Helper object for using mwx::stream
Use operators and methods provided by 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

Type that allows direct use of stream methods
The 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

Container class with FIFO queue structure
This is a container class with FIFO queue structure.
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.

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

Base class for handling input/output streams
This is a base class for handling input/output streams.
  • 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.
  • This class defines common processing such as the print method and the << operator, and calls methods like write() 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.

ParameterDescription
Return int0: 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.

ParameterDescription
nThe character to output.
Return size_t1 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.

ParameterDescription
outThe character to output
vpPointer 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.

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.

ParameterDescription
valThe numeric type to format and output
baseOutput format BIN binary / OCT octal / DEC decimal / HEX hexadecimal
placeNumber of decimal places
Return size_tNumber 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 TypeDescription
charOutputs one byte (does not format as a number)
intOutputs integer (printf “%d”)
doubleOutputs number (printf “%.2f”)
uint8_tOutputs one byte (same as char type)
uint16_tOutputs 2 bytes (big endian order)
uint32_tOutputs 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::crlfOutputs newline CRLF
mwx::flushFlushes 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.

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 TypeDescription
centisecSets timeout duration in 1/10 second units. Specifying 0xff disables timeout.

Error Values

ValueMeaning
0No error
1Error 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.

Below are the types that can be read and stored.

Argument TypeDescription
uint8_t, char_tReads one byte
uint16_tReads 2 bytes (big endian order)
uint32_tReads 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

printf format input
This is a helper class that writes format specifiers for the << 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, call fctprintf() 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.

ParameterDescription
fmtFormat 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.

1.1.4.10.2 - mwx::bigendian

Data output in big-endian order
This is a helper class that outputs numeric types as big-endian byte sequences for the << operator of mwx::stream.
Serial << mwx::bigendian(0x1234abcdUL);

// output binary -> 0x12 0x34 0xab 0xcd

Constructor

template <typename T>
bigendian::bigendian(T v)
ParameterDescription
vA value of type uint16_t or uint32_t

1.1.4.10.3 - mwx::crlf

Output of newline code
An instance of a helper class to output newline code (CR LF) for the << operator of mwx::stream.
Serial << "hello world!" << mwx::crlf;

1.1.4.10.4 - mwx::flush

Force output of the output buffer
Flushes the output buffer of 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

Helper object
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() returns false.
    • 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.

whencePosition set
MWX_SEEK_SETSets from the beginning. offset of 0 means the same as rewind().
MWX_SEEK_CURMoves by offset from the current position.
MWX_SEEK_ENDSets 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

State management
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

Various callback functions
These are callback functions where the application description is written. Callback means that it is called from the system (library). By defining several callback functions, the user describes the behavior of the system.

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 -+

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 -+

1.1.5.1 - setup()

Initialization process
Called at the beginning of code execution; write initialization code here.

1.1.5.2 - begin()

Initialization process (after TWENET initialization)
Called only once just before the first call of the 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()

Loop processing
This is the main loop of the application. After the loop ends, the CPU transitions to DOZE mode and waits for the next interrupt with low power consumption.

In Act, most processing is written inside this loop.

1.1.5.4 - wakeup()

Processing after waking from sleep
Called before transitioning to loop() after waking from sleep, this function includes procedures for initialization after waking and branching processes according to the wake-up state.

1.1.5.5 - init_coldboot()

Initialization process (before peripheral initialization)
Called at the re-initialization of code execution, before peripheral API and initialization have been performed.

1.1.5.6 - init_warmboot()

Process after waking from sleep (before peripheral initialization)
Called again after waking from sleep, before the peripheral API is initialized.

1.1.5.7 - on_rx_packet()

Processing upon packet reception
Describes the process when a received packet is received.
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).

1.1.5.8 - on_tx_comp()

Processing upon packet transmission completion
Describes the processing performed when the transmission is completed.
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

An advanced framework for implementing complex applications
In Behavior, defining a class in a specified manner allows it to be registered with the 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

A sample behavior using the Ambient Sensor PAL

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

RoleExample
ParentMONOSTICK BLUE or RED
ChildBLUE 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

Global Functions

1.1.7.1 - System Functions

Functions for handling time and random numbers

1.1.7.1.1 - millis()

Get system time
Gets the system time in milliseconds.
uint32_t millis()

The system time is updated by TickTimer interrupts.

1.1.7.1.2 - delay()

Delay processing
Performs a delay using polling.
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.

1.1.7.1.3 - delayMicroseconds()

Delay processing (microseconds)
Performs a delay using polling (specified in microseconds).
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.

1.1.7.1.4 - random()

Random number generation
Generates a random number.
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

Functions to handle DIO ports

The following functions are used to operate General Purpose Digital IO (DIO).

  • pinMode()
  • digitalWrite()
  • digitalRead()
  • attachIntDio()
  • detachIntDio()

Constants

Pin Names and Numbers

DefinitionName
const uint8_t PIN_DIGITAL::DIO0 .. 19DIO pins 0 to 19
const uint8_t PIN_DIGITAL::DO0 .. 1DO pins 0,1

Pin Modes (DIO0..19)

The following enumerated values are handled by the type E_PIN_MODE.

DefinitionPull-upName
PIN_MODE::INPUTNoInput
PIN_MODE::OUTPUTNoOutput
PIN_MODE::INPUT_PULLUPYesInput with Pull-up
PIN_MODE::OUTPUT_INIT_HIGHNoOutput (initial state HIGH)
PIN_MODE::OUTPUT_INIT_LOWNoOutput (initial state LOW)
PIN_MODE::WAKE_FALLINGNoInput, wake pin, falling edge
PIN_MODE::WAKE_RISINGNoInput, wake pin, rising edge
PIN_MODE::WAKE_FALLING_PULLUPYesInput, wake pin, falling edge with pull-up
PIN_MODE::WAKE_RISING_PULLUPYesInput, wake pin, rising edge with pull-up
PIN_MODE::DISABLE_OUTPUTYesReturn to input state

Pin Modes (DO0,1)

The following enumerated values are handled by the type E_PIN_MODE.

DefinitionName
PIN_MODE::OUTPUTOutput
PIN_MODE::OUTPUT_INIT_HIGHOutput (initial state HIGH)
PIN_MODE::OUTPUT_INIT_LOWOutput (initial state LOW)
PIN_MODE::DISABLE_OUTPUTStop output setting

Pin States

The following enumerated values are handled by the type E_PIN_STATE.

DefinitionValueName
PIN_STATE::HIGH1HIGH level (=Vcc level)
PIN_STATE::LOW0LOW level (=GND level)

Pin Rising and Falling Edges

The following enumerated values are handled by the type E_PIN_INT_MODE.

DefinitionName
PIN_INT_MODE::FALLINGFalling edge
PIN_INT_MODE::RISINGRising edge

1.1.7.2.1 - pinMode()

Initialization function
Configures the settings for DIO (General Purpose Digital IO) pins.
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.

1.1.7.2.2 - digitalWrite()

Digital output function
Changes the setting of a digital output pin.
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.

1.1.7.2.3 - digitalRead()

Digital input function
Reads the value of a port configured as input.
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.

1.1.7.2.4 - attachIntDio()

Function to register a DIO interrupt handler
Registers a DIO interrupt handler.
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()

Function to unregister a DIO interrupt handler
Unregisters a DIO interrupt handler.
void detachIntDio(uint8_t u8pin)

1.1.7.2.6 - digitalReadBitmap()

Digital input function (batch)
Reads the values of the input-configured ports in batch.
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

Other utility functions

1.1.7.3.1 - Printf Implementation

Functionality similar to C standard printf
The MWX library provides an implementation similar to the commonly used 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.

1.1.7.3.2 - pack_bits()

Set bits to 1 at specified positions
Sets bits to 1 at the specified positions.
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)).

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()

Create a bitmap from specified bit positions
Extracts values from specified bit positions in an integer and constructs a bitmap in the specified order.
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

Conversion between byte arrays and 16/32-bit integers
Generates 16/32-bit integers from byte arrays, or generates byte arrays from 16/32-bit integers.

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()

Generate a byte sequence by concatenating element data
Generates a byte sequence by concatenating element data.
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 TypeBytesDescription
uint8_t1
uint16_t2Stored in big-endian order
uint32_t4Stored in big-endian order
uint8_t[N]NFixed-length array of uint8_t
std::pair<char*,N>NPair 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 TypeBytesDescription
uint8_t1
uint16_t2Stored in big-endian order
uint32_t4Stored in big-endian order
uint8_t[N]NFixed-length array of uint8_t
std::pair<char*,N>NPair 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()

“Decompose a byte sequence and store it into variables”
Decompose a byte sequence and store it into variables.
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 bytesData lengthExplanation
uint8_t1
uint16_t2Expanded as big-endian order
uint32_t4Expanded as big-endian order
uint8_t[N]NFixed-length array of uint8_t
std::pair<char*,N>NA 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

Checksum calculation
Calculates values commonly used in checksum computations.
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.

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()

Calculate quotient and remainder when divided by 10, 100, or 1000
Calculates the quotient and remainder when divided by 10, 100, or 1000.
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.

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 parameterDescription
DIVFMT::STDStandard output, fills insufficient digits with spaces, and adds - only for negative values.
DIVFMT::PAD_ZEROFills insufficient digits with 0.
DIVFMT::SIGN_PLUSAdds + sign for positive values as well.
DIVFMT::PAD_ZERO_SIGN_PLUSFills insufficient digits with 0 and adds + sign for positive values.
DIVFMT::SIGN_SPACEAdds a space sign instead of + for positive values.
DIVFMT::PAD_ZERO_SIGN_SPACEFills 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

Optimized value scaling processing
Scale (expand/contract) between 8bit values (such as 0..255) and user-friendly 0..1000 (per mille, ‰) values. To achieve low computational cost, division (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()

Simplifies the syntax for placement new
Simplifies the syntax of placement new.
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

External Libraries
This section introduces external libraries that can be used with MWX.
  • 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

Lightweight template library
EASTL is a standard template library (containers and algorithms) maintained by Electronic Arts, implemented in the style of C++ STL (Standard Template Library). However, it was developed for the highly constrained environment of game console development, so it provides containers and algorithms designed for environments with strict memory handling constraints.

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 calling vsnprintf_() 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

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).

1.1.9 - Board Behavior (BRD)

Hardware Abstraction Layer
Board Behaviors are collections of procedures for handling hardware connected to the TWELITE module.
  • Definition of constants (e.g., pin numbers)
  • Hardware initialization
  • Handling sensors and similar peripherals

1.1.9.1 - <BRD_APPTWELITE>

Board behavior assuming the same wiring as the “Extremely Simple! Standard App”

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

Common definitions for the TWELITE PAL series
TWELITE PAL hardware shares common components, and board behaviors define a shared interface for those components.

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.

ModeDescription
LED_TIMER::BLINKBlinks the LED. Toggles ON/OFF every tick ms. After waking from sleep, it resets and starts ON.
LED_TIMER::ON_RXTurns on the LED for tick ms when a packet is received.
LED_TIMER::ON_TX_COMPTurns 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.

1.1.9.2.1 - <PAL_NOTICE>

For NOTICE PAL

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.

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

DefinitionDescription
PAL_NOTICE::LED_OFFOff
PAL_NOTICE::LED_ONOn (PWM brightness control)
PAL_NOTICE::LED_BLINKBlinking
PAL_NOTICE::LED_NOPNo change

LED Identifiers

DefinitionDescription
PAL_NOTICE::LED_RRed LED
PAL_NOTICE::LED_GGreen LED
PAL_NOTICE::LED_BBlue LED
PAL_NOTICE::LED_WWhite LED

Register Brightness Settings

DefinitionDescription
PAL_NOTICE::LED_REG_MAX_PWMStandard brightness PWM register value (approx. 50%)
PAL_NOTICE::LED_REG_BOOST_PWMBoost 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.

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>

For Ambient Sensor PAL
This board behavior is for the Ambient Sensor PAL.

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>

For Open-Close Sensor PAL

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>

For Motion Sensor PAL

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>

For TWELITE ARIA
This board behavior supports peripherals on the TWELITE 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.

ValueDescription
LED_TIMER::BLINKBlinks 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_RXTurns on the LED for the specified tick duration [ms] when a packet is received.
LED_TIMER::ON_TX_COMPTurns 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>

For TWELITE CUE
This board behavior supports peripherals on the TWELITE 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.

ValueDescription
LED_TIMER::BLINKBlinks the LED. Toggles ON/OFF every tick milliseconds. Resets counter after sleep and starts ON.
LED_TIMER::ON_RXTurns on LED for tick milliseconds upon packet reception.
LED_TIMER::ON_TX_COMPTurns 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>

For MONOSTICK
This board behavior is for MONOSTICK. It includes procedures for controlling the built-in watchdog timer and LED.

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.

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.

mode accepts the following parameters. tick specifies the lighting duration in milliseconds [ms]; see the descriptions for each mode below.

ParameterMeaning
LED_TIMER::BLINKThe LED blinks. ON/OFF toggles every tick milliseconds. After waking from sleep, the count resets and starts in the ON state.
LED_TIMER::ON_RXLights the LED for tick milliseconds upon packet reception.
LED_TIMER::ON_TX_COMPLights the LED for tick milliseconds upon transmission completion.

1.1.10 - Sensor Devices (SNS)

Standardized procedures for sensors and various devices
Provides classes that standardize procedures for sensors and various devices.

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.

1.1.10.1 - SHTC3

Temperature and Humidity Sensor
This is a temperature and humidity sensor that uses the I2C bus.

Processing Flow

  1. Wire.begin(): Initialize the bus
  2. .begin(): Start sensor operation
  3. Wait a few milliseconds
  4. .available() becomes true
  5. .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

Temperature and Humidity Sensor
This is a temperature and humidity sensor using the I2C bus.

Processing Flow

  1. Wire.begin(): Initialize the bus
  2. .setup(): Initialize the sensor
  3. .begin(): Start the sensor
  4. Wait for a few milliseconds
  5. .available() becomes true
  6. .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

Illuminance sensor
This is an illuminance sensor that uses the I2C bus.

Processing Flow

  1. Wire.begin(): Initialize the bus
  2. .begin(): Start sensor operation
  3. Wait for 50ms
  4. .available() becomes true
  5. .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

Accelerometer
This is an accelerometer that uses the SPI bus.

Operation Flow

  1. .begin(): Start sensor operation
  2. PIN_SNS_INT interrupt or available(): FIFO queue reaches the specified number of samples
  3. .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.

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 ModeDescription
MODE_LP_1HZ_UNOFFICIAL1Hz Low Power (unofficial)
MODE_LP_2HZ_UNOFFICIAL2Hz Low Power (unofficial)
MODE_LP_7HZ_UNOFFICIAL7Hz Low Power (unofficial)
MODE_LP_14HZ14Hz Low Power (default)
MODE_LP_28HZ28Hz Low Power
MODE_LP_54HZ54Hz Low Power
MODE_LP_105HZ105Hz Low Power
MODE_LP_210HZ210Hz Low Power
MODE_LP_400HZ400Hz Low Power
MODE_ULP_25HZ25Hz Ultra Low Power
MODE_ULP_50HZ50Hz Ultra Low Power
MODE_ULP_100HZ100Hz Ultra Low Power
MODE_ULP_190HZ190Hz Ultra Low Power
MODE_ULP_380HZ380Hz Ultra Low Power
conf[16:23] Acceleration RangeDescription
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

Environmental sensor
This is a pressure, temperature, and humidity (humidity only for BME280) sensor using the I2C bus.

Process Flow

  1. Wire.begin(): Initialize the bus
  2. .setup(): Initialize the sensor
  3. .begin(): Start sensor operation
  4. Wait for several milliseconds
  5. .available() becomes true
  6. .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, and 0x58 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

LED Driver
This is the LED driver used in NOTICE PAL.

Processing Flow

  1. Wire.begin(): Initialize the bus
  2. .setup(): Initialize the class object
  3. .reset(): Initialize the driver
  4. 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.

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.

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_OFFOFF
SNS_PCA9632::LED_ONON
SNS_PCA9632::LED_PWMPWM brightness control
SNS_PCA9632::LED_BLINKBlink control (group PWM)
SNS_PCA9632::LED_NOPDo 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

Temperature and Humidity Sensor
This is a temperature and humidity sensor that uses the I2C bus.

Processing Flow

  1. Wire.begin(): Initialize the bus
  2. .begin(): Start sensor operation
  3. Wait a few milliseconds
  4. .available() becomes true
  5. .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)

Abstraction layer for wireless communication using TWELITE NET
Network Behavior defines addressing and delivery control for sending and receiving IEEE802.15.4 MAC layer packets.
  • <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>

A simple relay network
This is a network behavior implementing a simple relay network.
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 IDRole
0x00Parent Station
0x01..0xEFChild Station
0xFEChild 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 IDMeaning
0x00Specifies the parent from a child. Invalid when specified from the parent.
0x01..0xEFSpecifies a specific child station.
0xFEBroadcast to all child stations.
0xFFBroadcast 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 is 16. 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 is 1000 ms.
  • tickscale is the time unit for timeout management, 2^tickscale ms. Time is managed with 7 bits, so set so that 127*(2^tickscale) > timeout_ms. Default is 5 (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 to true allows receiving plaintext packets with the same application ID and channel.

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 LayerEncryptionMaximum Payload
<NWK_SIMPLE>None91
<NWK_SIMPLE>Enabled89
  • 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>

Layered Tree Network
This is a network behavior that implements a simple relay network.

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 of NWK_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

Abstraction layer for interactive mode
Setting behavior is a behavior for using configuration CUI via interactive mode. The interface for configuration is performed through serial port input and output. Interactive configuration using terminal software such as TWELITE STAGE APP / TeraTerm / screen is possible.

1.1.12.1 - <STG_STD>

Minimal configuration behavior
<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

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 IDContent
APPIDApplication ID
LOGICALIDLogical Device ID (8bit)
CHANNELChannel
CHANNELS_3Channel (up to 3 channels)
POWER_N_RETRYPower and retry count
OPTBITSOption 1
OPT_DWORD2Option 2
OPT_DWORD3Option 3
OPT_DWORD4Option 4
ENC_MODEEncryption mode
ENC_KEY_STRINGEncryption key (string input)

<STG_STD> defines representative settings and four freely usable 32bit values. These can be used freely by the user.

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().

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.

MethodContent
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.

TargetItem IDContent
the_tweliteAPPIDReflected as TWENET::appid(value)
CHANNELReflected as TWENET::channel(value). ※ Not applied when SETTINGS::ch_multi() is specified
CHANNELS_3Reflected as TWENET::chmask(value). ※ Applied only as channel mask when SETTINGS::ch_multi() is specified
POWER_N_RETRYReflected as TWENET::tx_power(value) and TWENET::mac_retry_count(value). Note: <NWK_SIMPLE> retransmission uses the same value.
<NWK_SIMPLE>LOGICALIDReflected as NWK_SIMPLE::logical_id(LID)
POWER_N_RETRYReflected 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
APPIDApplication ID
LOGICALIDLogical ID (0..100)
CHANNELChannel
CHANNELS_3Channel (multiple)
POWER_N_RETRYPower and retry settings
OPTBITSOption bits
UARTBAUDUART baud rate setting
OPT_DWORD2Option bits 2
OPT_DWORD3Option bits 3
OPT_DWORD4Option bits 4
ENC_MODEEncryption mode
ENC_KEY_STRINGEncryption 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

Revision history of the TWELITE STAGE SDK

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 to cbToCoNet_??? functions.
      • Introduced MWX_USE_ALIAS macro in mwx_appcore.c. If defined, it aliases the MWX_cbToCoNet???() callback function directly to cbToCoNet???() to suppress redundant function calls.
    • 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.
  • 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. The on_begin() used for board behavior was called the_twelite.begin() procedure in ::setup().
  • Improved the definitions of mwx::G_BYTE(), mwx::G_WORD(), and mwx::G_DWORD() to allow their use with r-values.
  • Fixed an issue where fmt in Serial::println(T, fmt) did not output correctly when DEC or OCT was specified.
  • NAK was not being sent correctly by the Wire object.
  • Improved serial_parser to allow output with Serial << even with r-values, as shown below:
    • Serial << serparser_attach(PARSER::ASCII, buf.begin(), buf.size())
  • Added explicit to the operator bool() method.
  • Renamed mwx::S_OCTET() to mwx::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 of setup(), loop(), etc.
  • Added mwx::stream::vprintfmt() to support va_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 to mwx_debug.h. (An experimental attempt to use the NWK_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, call the_vapp.cbToCoNet_vRxEvent(), otherwise call on_rx_packet().
    • cbToCoNet_vTxEvent(): If the event is handled by network behavior, call the_vapp.cbToCoNet_vTxEvent(), otherwise call on_tx_comp().
    • cbToCoNet_vNwkEvent(): If the event is handled by network behavior, call .cbToCoNet_vNwkEvent(), otherwise call on_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 default APP_ID for interactive mode settings.
  • [GOLD] Added support for TWELITE GOLD for the MC3630 sensor driver.
  • added div100_128th() to convert 128th value into div100() 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() and get_on_boot_voltage() in div_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 when pinMode() is called for two or more ports. (storing bitmap state internally in mwx codes)
  • fixed attachIntDio() detachIntDio() to consider behavior of vAHIDioInterruptEdge().
  • fixed that repeat count of <NWK_SIMPLE> is not incremented when it’s repeating.

0.2.0 - 2022-03-01

Library NameDependency Version
mwx0.2.0
twesettings0.2.6
TWENET C1.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() to G_BYTE().
  • Changed the order of vAHI_DioInterruptEnable() in attachIntDio().
  • 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 NameDependency Version
mwx0.1.9
twesettings0.2.6
TWENET C1.3.5

Main changes

  • Added board support BRD_ARIA and sensor definition SHT4x 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 NameDependency Version
mwx0.1.8
twesettings0.2.6
TWENET C1.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 NameDependency Version
mwx0.1.7
twesettings0.2.6
TWENET C1.3.4

Main changes

0.1.6 - 2020-10-09

Library NameDependency Version
mwx0.1.6
twesettings0.2.5
TWENET C1.3.4

Main changes

  • Added div100() that calculates quotient and remainder and outputs to Serial etc.
  • Changed implementation of smplbuf<> array class. To reduce memory usage, stopped inheriting mwx::stream and defined separate inherited and helper classes.
  • Added functions mwx_printf() and mwx_snprintf()
  • Added the_twelite.stop_watchdog() and the_twelite.restart_watchdog()
  • Maintained mwx::stream: Removed operator bool(). Specified timeout of 0xff 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 encrypted
    • STG_STD::u8encmode(): Gets encryption setting in interactive mode
    • STG_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 for available(), read() to only void*, 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 to true 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");
        ;
  • 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.

0.1.5 - 2020-08-05

Library NameDependency Version
mwx0.1.5
twesettings0.2.5
TWENET C1.3.4

Main changes

  • Added setting behavior (interactive mode feature)
  • Implemented channel manager chmgr

0.1.4 - 2020-07-29

Library NameDependency Version
mwx0.1.4
twesettings0.2.4
TWENET C1.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.

https://github.com/monowireless/mwx/releases/tag/0.1.3

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

https://github.com/monowireless/mwx/releases/tag/0.1.2

0.1.1 - 2020-02-28

Main changes

  • Fixed issue with handling of relay flags inside packets

https://github.com/monowireless/mwx/releases/tag/0.1.1

0.1.0 - 2019-12-23

First release (included in SDL December 2019 issue)

https://github.com/monowireless/mwx/releases/tag/0.1.0

2 - TWELITE SDK / MWSDK (Legacy)

A low-level toolchain for working with TWELITE

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)

Latest version

3 - TWELITE Wings API / MWings

A library used on a terminal connected to the TWELITE parent device
MWings is a library used on a terminal connected to a TWELITE programmed with the parent/repeater application (App_Wings). It interprets the formatted strings output by App_Wings and provides the data received by the parent device to the terminal. It also constructs commands to App_Wings to control child devices.

3.1 - TWELITE Wings API / MWings for 32-bit Arduinos

MWings for 32-bit Arduino boards
TWELITE Wings API for 32-bit Arduino boards.

3.1.1 - TWELITE Wings API / MWings for 32-bit Arduinos

Latest Version
TWELITE Wings API for 32-bit Arduino boards.

3.1.1.1 - List of Data Types and Procedures

List of MWings-specific data types and procedures for 32-bit Arduino boards
This is a list of MWings-specific data types and procedures. Click here for a list of classes.

Structures

BarePacket

Stores raw data extracted from the packet received by the parent device from a child device.

MWings_Common.h

Data

TypeNameDescription
uint8_t*u8PayloadPayload data converted to binary (excluding :, checksum, and CRLF)
uint16_tu16PayloadSizeByte size of the above data
uint8_tu8ChecksumChecksum of the above data

Procedures

Type and NameDescription
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.

MWings_Common.h

Data

TypeNameDescription
uint32_tu32SourceSerialIdSerial ID of the sender
uint8_tu8SourceLogicalIdLogical device ID of the sender
uint16_tu16SequenceNumberSequence number
uint8_tu8LqiLQI
uint16_tu16SupplyVoltageSupply voltage (mV)

ParsedAppTwelitePacket

Derived from mwings::ParsedPacketBase

Structure that stores data received by the parent device from a child device running the “Super Easy! Standard App”.

AppTwelitePacketParser.h

Data

TypeNameDescription
uint8_tu8DestinationLogicalIdLogical device ID of the recipient
uint8_tu8RelayCountNumber of relays
boolbPeriodictrue if the packet is a periodic transmission
bool[4]bDiChangedtrue if DI1–4 changed
bool[4]bDiStatetrue if DI1–4 are in Low state
uint16_t[4]u16AiVoltageInput 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.

AppIoPacketParser.h

Data

TypeNameDescription
uint8_tu8RelayCountNumber of relays
bool[12]bDiStatetrue if each DI is in Low state
bool[12]bDiValidtrue if each DI is valid
bool[12]bDiInterrupttrue 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).

AppAriaPacketParser.h

Data

TypeNameDescription
uint32_tu32RouterSerialIdSerial ID of the first relay device
0x80000000 if not relayed (v1.2.2+)
int16_ti16Temp100xTemperature ×100 (Celsius)
uint16_tu16Humid100xRelative humidity ×100 (%)
uint8_tu8MagnetStateMagnet Event ID
boolbMagnetStateChangedtrue if magnet sensor state changed
Magnet Event ID
IDDescription
0x00No magnet nearby
0x01North pole is nearby
0x02South 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).

AppCuePacketParser.h

Data

TypeNameDescription
uint32_tu32RouterSerialIdSerial ID of the first relay device
0x80000000 if not relayed (v1.2.2+)
int16_t[10]i16SamplesXX-axis acceleration samples (mG)
int16_t[10]i16SamplesYY-axis acceleration samples (mG)
int16_t[10]i16SamplesZZ-axis acceleration samples (mG)
uint8_tu8SampleCountNumber of samples
boolbHasAccelEventtrue if there is an acceleration event
uint8_tu8AccelEventAcceleration Event ID
uint8_tu8MagnetStateMagnet Event ID
boolbMagnetStateChangedtrue if magnet sensor state changed
Acceleration Event ID
IDDescription
0x01~0x06Dice
0x08Shake
0x10Move
Magnet Event ID
IDDescription
0x00No magnet nearby
0x01North pole is nearby
0x02South 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).

AppPalAmbPacketParser.h

Data

TypeNameDescription
uint32_tu32RouterSerialIdSerial ID of the first relay device
0x80000000 if not relayed (v1.2.2+)
uint16_tu16Ai1VoltageAI1 input voltage (mV)
int16_ti16Temp100xTemperature ×100 (Celsius)
uint16_tu16Humid100xRelative humidity ×100 (%)
uint32_tu32IlluminanceIlluminance (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).

AppPalMotPacketParser.h

Data

TypeNameDescription
uint32_tu32RouterSerialIdSerial ID of the first relay device
0x80000000 if not relayed (v1.2.2+)
uint16_tu16Ai1VoltageAI1 input voltage (mV)
int16_t[16]i16SamplesXX-axis acceleration samples (mG)
int16_t[16]i16SamplesYY-axis acceleration samples (mG)
int16_t[16]i16SamplesZZ-axis acceleration samples (mG)
uint8_tu8SampleCountNumber of samples
uint16_tu16SamplingFrequencySampling 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).

AppPalOpenClosePacketParser.h

Data

TypeNameDescription
uint32_tu32RouterSerialIdSerial ID of the first relay device
0x80000000 if not relayed (v1.2.2+)
uint16_tu16Ai1VoltageAI1 input voltage (mV)
uint8_tu8MagnetStateMagnet Event ID
boolbMagnetStateChangedtrue if magnet sensor state changed
Magnet Event ID
IDDescription
0x00No magnet nearby
0x01North pole is nearby
0x02South 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).

AppUartAsciiPacketParser.h

Data

TypeNameDescription
uint8_tu8CommandIdCommand type (response ID)
uint8_t*u8DataData
uint16_tu16DataSizeData 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

TypeNameDescription
uint32_tu32DestinationSerialIdDestination serial ID
uint8_tu8CommandIdCommand type (response ID)
uint8_t*u8DataData
uint16_tu16DataSizeData length

ParsedActPacket

Derived from mwings::ParsedPacketBase

Structure that stores data received by the parent device from a child device running the act app.

ActPacketParser.h

Data

TypeNameDescription
uint8_tu8CommandIdCommand type (response ID)
uint8_t*u8DataData
uint16_tu16DataSizeData length

mwings::CommandBase

Abstract structure that stores command data sent from the parent device to a child device.

MWings_Common.h

Data

TypeNameDescription
uint8_tu8DestinationLogicalIdDestination logical device ID

Procedures

Type and NameDescription
bool isValid()Returns true if the data is valid (pure virtual function)

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”.

AppTweliteCommandSerializer.h

Data

TypeNameDescription
bool[4]bDiToChangetrue to change the state of each DO1-4
bool[4]bDiStatetrue to set each DO1-4 to Low state
bool[4]bPwmToChangetrue to change the state of each PWM1-4
uint16_t[4]u16PwmDutyDuty 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.

AppIoCommandSerializer.h

Data

TypeNameDescription
bool[12]bDiToChangetrue to change the state of each O1-12
bool[12]bDiStatetrue 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

TypeNameDescription
AppPalNoticeColoreColorLighting color
AppPalNoticeBlinkSpeedeBlinkSpeedBlinking speed
uint8_tu8BrightnessBrightness (0-15)
uint16_tu16DurationInSecLighting 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

TypeNameDescription
AppPalNoticeRGBWColorsRGBWColorLighting color (RGBW)
uint8_tu8BlinkDutyPercentageLighting time ratio (%)
floatfBlinkPeriodInSecBlinking period (seconds)
uint16_tu16DurationInSecLighting 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

TypeNameDescription
uint8_tu8EventIdEvent 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).

AppUartAsciiCommand.h

Data

TypeNameDescription
uint8_tu8CommandIdCommand type (response ID)
uint8_t*u8DataData
uint16_tu16DataSizeData length

AppPalNoticeRGBWColor

Structure that defines the lighting color (RGBW) used in AppPalNoticeDetailedCommand.

AppPalNoticeDetailedCommandSerializer.h

Data

TypeNameDescription
uint8_tredR (0-15)
uint8_tgreenG (0-15)
uint8_tblueB (0-15)
uint8_twhiteW (0-15)

Procedures

Type and NameDescription
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

IdentifierValueDescription
AppPalNoticeColor::RED0Red
AppPalNoticeColor::GREEN1Green
AppPalNoticeColor::BLUE2Blue
AppPalNoticeColor::YELLOW3Yellow
AppPalNoticeColor::PURPLE4Purple
AppPalNoticeColor::LIGHT_BLUE5Light blue
AppPalNoticeColor::WHITE6White
AppPalNoticeColor::WARM_WHITE7Warm white

AppPalNoticeBlinkSpeed

enum class based on uint8_t

Enumeration that defines the blinking speed used in AppPalNoticeCommand.

AppPalNoticeCommandSerializer.h

IdentifierValueDescription
AppPalNoticeBlinkSpeed::ALWAYS_ON0Always on
AppPalNoticeBlinkSpeed::SLOW1Slow blinking
AppPalNoticeBlinkSpeed::MEDIUM2Medium blinking
AppPalNoticeBlinkSpeed::FAST3Fast blinking

Other Data Types

Procedures

GetAppTweliteSerializedCommandPayloadSize()

constexpr function ?

Returns the payload size (in bytes) of the serialized fixed-length data for AppTweliteCommand.

AppTweliteCommandSerializer.h

Type and NameDescription
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 NameDescription
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 NameDescription
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 NameDescription
int GetAppPalNoticeEventSerializedCommandPayloadSize()Returns the number of bytes

3.1.1.2 - Class List

List of MWings classes for 32-bit Arduino boards
This is a list of classes.

3.1.1.2.1 - mwings::MWings Class

The main MWings class for 32-bit Arduino boards
This is an explanation of the mwings::MWings class.

Constructor

MWings()

Constructor. Initializes internal variables.

MWings()

MWings.h

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);

MWings.cpp

Arguments

TypeNameDescriptionOptionalRemarks
HardwareSerial&serialPort communicating with TWELITE
intindicatorPinPin connected to status LED🆗Can be omitted with -1
intresetPinTWELITE’s RST pin🆗Can be omitted with -1
intprogramPinTWELITE’s PRG pin🆗Can be omitted with -1
uint8_tchannelFrequency channel🆗Default is 18
uint32_tappIdApplication ID🆗Default is 0x67720102
uint8_tretryCountNumber of retries🆗0-9
uint8_ttxPowerTransmission power🆗0-3
intrxBufferSizeSize of packet reception buffer🆗Binary-based
inttimeoutTimeout for each packet🆗Until reception completion
uint32_tencryptKeyEncryption key🆗Disabled if 0, available from v1.2.3+
HardwareSerial*debugSerialDebug output port🆗

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

end()

Initializes all internal variables.

inline void end()

MWings.h

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();

MWings.h

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(BarePacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppTwelitePacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppIoPacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppAriaPacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppCuePacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppPalOpenClosePacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppPalAmbPacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppPalMotPacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppUartAsciiPacket&)callbackEvent handler

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))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedAppUartAsciiExtendedPacket&)callbackEvent handler

Return Value

None

on() <ParsedActPacket>

Registers a handler to process data sent from act child devices.

inline void on(void (*callback)(const ParsedActPacket& packet))

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
void (*)(ParsedActPacket&)callbackEvent handler

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)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
uint8_t*payloadPayloadBetween : and LRC
intpayloadSizePayload size
uint8_tchecksumChecksumLRC of the payload

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

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)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
uint8_t*payloadPayloadBetween : and LRC
intpayloadSizePayload size

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

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)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
uint8_tlogicalIdDestination logical device ID
uint8_tcommandIdCommand type
uint8_t*payloadPayloadBetween : and LRC
intpayloadSizePayload size
uint8_tchecksumChecksumLRC of the payload

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

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)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
uint8_tlogicalIdDestination logical device ID
uint8_tcommandIdCommand type
uint8_t*payloadPayloadBetween : and LRC
intpayloadSizePayload size

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

send() <AppTweliteCommand>

Super easy! Sends a command to operate standard app terminals to the parent device.

inline bool send(AppTweliteCommand& command)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
AppTweliteCommandcommandCommand data

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

send() <AppIoCommand>

Sends a command to operate remote control app terminals to the parent device.

inline bool send(AppIoCommand& command)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
AppIoCommandcommandCommand data

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

send() <AppPalNoticeCommand>

Sends a command to operate PAL app (notification PAL) terminals to the parent device.

inline bool send(AppPalNoticeCommand& command)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
AppPalNoticeCommandcommandCommand data

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

send() <AppPalNoticeDetailedCommand>

Sends a command (detailed format) to operate PAL app (notification PAL) terminals to the parent device.

inline bool send(AppPalNoticeDetailedCommand& command)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
AppPalNoticeDetailedCommandcommandCommand data

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

send() <AppPalNoticeEventCommand>

Sends a command (event) to operate PAL app (notification PAL) terminals to the parent device.

inline bool send(AppPalNoticeEventCommand& command)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
AppPalNoticeEventCommandcommandCommand data

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

send() <AppPalUartAsciiCommand>

Sends a command (simple format) to operate serial communication app (A mode) terminals to the parent device.

inline bool send(AppPalUartAsciiCommand& command)

MWings.h

Arguments

TypeNameDescriptionOptionalRemarks
AppPalUartAsciiCommandcommandCommand data

Return Value

TypeValueDescriptionRemarks
booltrueSuccess
falseError

3.2 - TWELITE Wings API / MWings for Python

MWings for Modern Python
This is the TWELITE Wings API for modern Python.

3.2.1 - TWELITE Wings API / MWings for Python

Latest Version
This is the TWELITE Wings API for modern Python.

3.2.1.1 - mwings module

mwings

This is a top-level module that is often used directly.

src/mwings/__init__.py

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

NameTypeDescription
portoptional strSerial port name: disabled if None
rx_buffer_sizeintSize of the receive buffer in bytes
timeoutintTimeout between receiving packets (ms)
tzoptional tzinfoTimezone applied to received data: UTC if None
debuggingboolDebug 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.

Parameters

None

Return value

None

add_listener()

@overload
add_listener(event, handler)
add_listener(event, handler)

Registers a receive handler.

Parameters

NameTypeDescription
eventcommon.PacketTypeIdentifier for the receive event
handlerCallable[[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

NameTypeDescription
eventcommon.PacketTypeIdentifier for the receive event

Return value

TypeValueDescription
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

NameTypeDescription
characterstrReceived data character: string of length 1
bytesReceived data character: bytes of length 1
intReceived data character: ASCII code
use_lfboolType of newline character: LF if True

Return value

TypeValueDescription
optional common.PacketTypecommon.PacketTypeParsed packet type
NoneNo parsed packet

Exceptions

  • RuntimeError Serial port is specified
  • ValueError Invalid character data detected

parse_line()

parse_line(line, use_lf=True)

Parses received data expressed as a single line string.

Parameters

NameTypeDescription
linestrReceived data string: a single line
use_lfboolType of newline character: LF if True

Return value

TypeValueDescription
optional common.PacketTypecommon.PacketTypeParsed packet type
NoneNo 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

TypeValueDescription
common.PacketType-Parsed packet type

Exceptions

  • RuntimeError Serial port is not specified

run()

run()

Runs a subthread that performs reception. Overrides threading.Thread.run().

Parameters

None

Return value

None

send()

@overload
send(data)
send(data)

Sends commands from the serial port.

Parameters

NameTypeDescription
datacommon.SomeCommandVarious command data
common.BarePacketRaw command data

Return value

TypeValueDescription
boolTrueSuccess
FalseFailure

Exceptions

  • RuntimeError Serial port is not specified

set_timezone()

set_timezone(tz)

Sets the timezone applied to received data.

Parameters

NameTypeDescription
tztzinfoAny timezone: ZoneInfo
NoneUTC

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

TypeValueDescription
optional common.PacketTypecommon.PacketTypeParsed packet type
NoneNo parsed packet

Exceptions

  • RuntimeError Serial port is not specified

timezone

@property
update()

Return value

TypeValueDescription
tzinfo-Timezone applied to received data

3.2.1.1.1 - mwings.common Module

Stores data and procedures used throughout the library.

Contains data and procedures used throughout the library.

src/mwings/common.py

AccelEvent

Identifiers for accelerometer events

Inherits from: enum.IntEnum

  • DICE_1 Dice: 1
  • DICE_2 Dice: 2
  • DICE_3 Dice: 3
  • DICE_4 Dice: 4
  • DICE_5 Dice: 5
  • DICE_6 Dice: 6
  • SHAKE Shake
  • MOVE Move
  • NONE No event

AppPalNoticeBlinkSpeed

Identifiers for AppPal notification blink speed

Inherits from: enum.IntEnum

  • ALWAYS_ON Always on
  • SLOW Slow blinking
  • MEDIUM Moderate blinking
  • FAST Fast blinking

AppPalNoticeColor

Identifiers for AppPal notification colors

Inherits from: enum.IntEnum

  • RED Red
  • GREEN Green
  • BLUE Blue
  • YELLOW Yellow
  • PURPLE Purple
  • LIGHT_BLUE Light blue
  • WHITE White
  • WARM_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

NameTypeDescription
redcommon.UInt8Red: 00xF
greencommon.UInt8Green: 00xF
bluecommon.UInt8Blue: 00xF
whitecommon.UInt8White: 00xF

You may pass a dictionary using ** unpacking.

u16()

u16()

Returns a 16-bit RGBW representation.

Parameters

None

Returns

TypeValueDescription
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

NameTypeDescription
payloadbytesBinary payload data
checksumoptional common.UInt8LRC8: Automatically calculated if None
logical_and_command_idoptional 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

NameTypeDescription
indexintPosition in payload

Returns

TypeValueDescription
common.Int16-Numeric data

i32_at()

i32_at(index)

Gets a signed 32-bit integer from the specified position.

Parameters

NameTypeDescription
indexintPosition in payload

Returns

TypeValueDescription
common.Int32-Numeric data

i8_at()

i8_at(index)

Gets a signed 8-bit integer from the specified position.

Parameters

NameTypeDescription
indexintPosition in payload

Returns

TypeValueDescription
common.Int8-Numeric data

u16_at()

u16_at(index)

Gets an unsigned 16-bit integer from the specified position.

Parameters

NameTypeDescription
indexintPosition in payload

Returns

TypeValueDescription
common.UInt16-Numeric data

u32_at()

u32_at(index)

Gets an unsigned 32-bit integer from the specified position.

Parameters

NameTypeDescription
indexintPosition in payload

Returns

TypeValueDescription
common.UInt32-Numeric data

u8_at()

u8_at(index)

Gets an unsigned 8-bit integer from the specified position.

Parameters

NameTypeDescription
indexintPosition in payload

Returns

TypeValueDescription
common.UInt8-Numeric data

u8_from()

u8_from(index)

Gets a byte sequence starting from the specified index.

Parameters

NameTypeDescription
indexintStarting index in payload

Returns

TypeValueDescription
optional bytesbytesPartial byte sequence
NoneInvalid index

CommandBase

Abstract base class for commands

Inherits from: ABC, pydantic.BaseModel

CommandBase()

CommandBase(*, destination_logical_id=120)

Parameters

NameTypeDescription
destination_logical_idcommon.UInt8Logical 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

TypeValueDescription
boolTrueValid
FalseInvalid

CommandSerializerBase

Static abstract base class for command serializers

Inherits from: ABC

serialize()

serialize(command)

Expands the given command into a raw byte sequence.

Parameters

NameTypeDescription
commandcommon.SomeCommandA command data object

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded packet data
NoneInvalid 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

NameTypeDescription
Tcommon.TElement type
lengthintNumber of elements
elementsIterable[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

TypeValueDescription
str-dtype identifier

FixedList[T]

A class representing a fixed-length list

Inherits from: MutableSequence[T]

FixedList[T]()

FixedList[T](length, initial_elements)

Parameters

NameTypeDescription
Tcommon.TType of elements
lengthintNumber of elements
initial_elementsIterable[T]Initial elements

Exceptions

  • ValueError if the number of elements is invalid

insert()

insert(index, value)

Inserts an element at the specified index.

Parameters

NameTypeDescription
indexintIndex to insert
valuecommon.TElement 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

NameTypeDescription
Tcommon.TType of elements
lengthintNumber of elements
elementsIterable[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

NameTypeDescription
valueoptional floatInitial 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

NameTypeDescription
valueoptional floatInitial 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

NameTypeDescription
valueoptional intInitial 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

TypeValueDescription
str-Hexadecimal string (lowercase)

Int32

Class to store a 32-bit integer

Inherits from: int, common.DtypedDecimal

Int32()

Int32(value=None)

Parameters

NameTypeDescription
valueoptional intInitial 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

NameTypeDescription
valueoptional intInitial 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 magnet
  • N_POLE_IS_CLOSE N pole is close
  • S_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

NameTypeDescription
Tcommon.TElement type
lengthintNumber of elements
elementsIterable[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

Parsers for interpreting packets and handling their data.
Parsers for interpreting packets and handling their data.

3.2.1.1.2.1 - mwings.parsers.app_twelite Module

Parsers for packets sent from the Standard App (App_TWELITE) and data structures to store their contents.

Parsers for packets sent from the Extremely simple! Standard App (App_Twelite) and data structures to handle the data.

src/mwings/parsers/app_twelite.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given raw packet.

Parameters

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketParsedPacket instanceParsed data
NoneParsing 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

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
destination_logical_idcommon.UInt8Destination logical device ID
relay_countcommon.UInt8Relay count
periodicboolWhether periodic transmission
di_changedcommon.CrossSectional[bool](4)Digital interface change presence
di_statecommon.CrossSectional[bool](4)Digital interface state
ai_voltagecommon.CrossSectional[common.UInt16](4)Analog interface voltages

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts parsed data to a pandas DataFrame.

Parameters

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only when other args are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only when other args are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only when other args are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None for no newline)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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.

Parsers for packets sent from the remote control app and data structures to store their contents.

src/mwings/parsers/app_io.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given raw packet.

Arguments

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketData of type ParsedPacketParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Always None because ADC is not used
relay_countcommon.UInt8Number of relays
di_changedcommon.CrossSectional[bool](12)Digital interface change status
di_statecommon.CrossSectional[bool](12)Digital interface state
di_interruptcommon.CrossSectional[bool](12)Digital interface interrupt status

You can pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data to a pandas DataFrame.

Arguments

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolInclude system information (only when other args are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolInclude system information (only when other args are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolInclude system information (only when other args are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None for no newline)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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.

Parsers for packets sent from App Aria and data structures to store their contents.

src/mwings/parsers/app_aria.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given raw packet.

Arguments

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketData of type ParsedPacketParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing time
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
router_serial_idcommon.UInt32Serial ID of the first relay device (0x80000000 if none) v1.0.13+
temp_100xcommon.Int16Temperature multiplied by 100 (°C)
humid_100xcommon.UInt16Relative humidity multiplied by 100
magnet_statecommon.MagnetStateMagnet state
magnet_state_changedboolWhether the magnet state has changed

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data to a pandas DataFrame format.

Arguments

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only if other arguments are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only if other arguments are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only if other arguments are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None for no line breaks)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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.

Parsers for packets sent from the TWELITE CUE mode and data structures to store their contents.

src/mwings/parsers/app_cue.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid and parsable
FalseInvalid and unparsable

parse()

parse(bare_packet)

Parses the given bare packet.

Parameters

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketParsedPacket typed dataParsed data
NoneUnparsable

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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
router_serial_idcommon.UInt32Serial ID of the first relay device (no relay is 0x80000000) v1.0.13+
sample_countcommon.UInt8Number of accelerometer samples per axis
samples_xcommon.TimeSeries[common.Int16]X-axis accelerometer samples
samples_ycommon.TimeSeries[common.Int16]Y-axis accelerometer samples
samples_zcommon.TimeSeries[common.Int16]Z-axis accelerometer samples
has_accel_eventboolPresence of accelerometer event
accel_eventcommon.AccelEventAccelerometer event
magnet_statecommon.MagnetStateMagnet state
magnet_state_changedboolWhether magnet state has changed

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data to a pandas DataFrame.

Parameters

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only when other arguments are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only when other arguments are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only when other arguments are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None for no newline)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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.

Parsers for packets sent from TWELITE CUE in PAL event mode (Dice/Move mode) and data structures to store their contents.

src/mwings/parsers/app_cue_pal_event.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given raw packet.

Arguments

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketData of type ParsedPacketParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
router_serial_idcommon.UInt32Serial ID of the first relay device (no relay is 0x80000000) v1.0.13+
ai1_voltagecommon.UInt16Voltage of AI1 (mV)
accel_eventcommon.AccelEventAcceleration event

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data into a pandas DataFrame format.

Arguments

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolInclude system information (only if other arguments are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolInclude system information (only if other arguments are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolInclude system information (only if other arguments are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None means no line breaks)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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.

Parsers for packets sent from PAL App (Open/Close PAL) and data structures to store their contents.

src/mwings/parsers/app_pal_openclose.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given raw packet.

Parameters

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketData of type ParsedPacketParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing time
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
router_serial_idcommon.UInt32Serial ID of the first relay device (0x80000000 if none) v1.0.13+
ai1_voltagecommon.UInt16Voltage of AI1 (mV)
magnet_statecommon.MagnetStateMagnet state
magnet_state_changedboolWhether the magnet state has changed

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data into a pandas DataFrame.

Parameters

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in DataFrame
excludeoptional set[str]Set of columns (members) to exclude from DataFrame
verboseboolWhether to include system information (only when other args are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only when other args are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort by keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in JSON
excludeoptional set[str]Set of keys (members) to exclude from JSON
verboseboolWhether to include system information (only when other args are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None for no newline)
sort_keysboolWhether to sort by keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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.

Parsers for packets sent from PAL App (Environmental PAL) and data structures to store their contents.

src/mwings/parsers/app_pal_amb.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, unparsable

parse()

parse(bare_packet)

Parses the given raw packet.

Parameters

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketParsedPacket instanceParsed data
NoneUnparsable

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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
router_serial_idcommon.UInt32Serial ID of first relay device (0x80000000 if none) v1.0.13+
ai1_voltagecommon.UInt16Voltage of AI1 (mV)
temp_100xcommon.Int16Temperature multiplied by 100 (°C)
humid_100xcommon.UInt16Relative humidity multiplied by 100
illuminancecommon.UInt32Illuminance (lx)

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data into a pandas DataFrame.

Parameters

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only if other args are None)

Returns

TypeDescription
pd.DataFrameConverted 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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only if other args are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only if other args are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of indentation spaces (None for no newlines)
sort_keysboolWhether to sort keys

Returns

TypeDescription
strConverted JSON string

model_*()

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).

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.

src/mwings/parsers/app_pal_mot.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given bare packet.

Arguments

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketParsedPacket instanceParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Sequence number
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Supply voltage (mV)
router_serial_idcommon.UInt32Serial ID of the first relay device (0x80000000 if none) v1.0.13+
ai1_voltagecommon.UInt16Voltage of AI1 (mV)
sample_countcommon.UInt8Number of acceleration samples per axis
samples_xcommon.TimeSeries[common.Int16]Acceleration samples on X axis
samples_ycommon.TimeSeries[common.Int16]Acceleration samples on Y axis
samples_zcommon.TimeSeries[common.Int16]Acceleration samples on Z axis
sampling_frequencycommon.UInt16Acceleration sampling frequency

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data into a pandas DataFrame.

Arguments

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only effective if other arguments are None)

Returns

TypeDescription
pd.DataFrameConverted 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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only effective if other arguments are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only effective if other arguments are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of spaces for indentation (None for no newlines)
sort_keysboolWhether to sort keys

Returns

TypeDescription
strConverted JSON string

model_*()

3.2.1.1.2.9 - mwings.parsers.app_uart_ascii Module

Parsers for packets sent from the serial communication app (format mode: simplified).

Parsers for packets sent from the serial communication app (format mode: simplified) and data structures to store their contents.

src/mwings/parsers/app_uart_ascii.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, can be parsed
FalseInvalid, cannot be parsed

parse()

parse(bare_packet)

Parses the given bare packet.

Parameters

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketAn instance of ParsedPacketParsed data
NoneCannot 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Not obtainable, always None
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Not obtainable, always None
supply_voltageoptional common.UInt16Not obtainable, always None
command_idcommon.UInt8Command ID
databytesData

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts parsed data into a pandas DataFrame.

Parameters

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only if other args are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only if other args are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in JSON
excludeoptional set[str]Set of keys (members) to exclude from JSON
verboseboolWhether to include system information (only if other args are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of indentation spaces (None for no newlines)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

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).

Parsers for packets sent from the serial communication app (format mode: extended) and data structures to store their contents.

src/mwings/parsers/app_uart_ascii_extended.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given bare packet.

Parameters

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketInstance of ParsedPacketParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Not available, always None
source_serial_idcommon.UInt32Sender’s serial ID
source_logical_idcommon.UInt8Sender’s logical device ID
lqicommon.UInt8Radio signal quality
supply_voltageoptional common.UInt16Not available, always None
destination_serial_idcommon.UInt32Receiver’s serial ID
command_idcommon.UInt8Command ID
databytesData

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts the parsed data into a pandas DataFrame.

Parameters

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only when other arguments are None)

Returns

TypeDescription
pd.DataFrameConverted 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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only when other arguments are None)
spreadboolWhether to split list-like data that is not time series
sort_keysboolWhether to sort keys

Returns

TypeDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only when other arguments are None)
spreadboolWhether to split list-like data that is not time series
indentoptional intNumber of spaces for indentation (None for no line breaks)
sort_keysboolWhether to sort keys

Returns

TypeDescription
strConverted JSON string

model_*()

3.2.1.1.2.11 - mwings.parsers.act Module

Parsers for packets sent from act and data structures to store their contents.

Parsers for packets sent from act and data structures to store their contents.

src/mwings/parsers/act.py

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

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
boolTrueValid, parsable
FalseInvalid, not parsable

parse()

parse(bare_packet)

Parses the given bare packet.

Arguments

NameTypeDescription
bare_packetcommon.BarePacketRaw packet data

Returns

TypeValueDescription
optional ParsedPacketParsedPacket instanceParsed data
NoneParsing 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.

NameTypeDescription
time_parsedoptional AwareDatetimeParsing timestamp
packet_typecommon.PacketTypePacket type
sequence_numberoptional common.UInt16Not available, always None
source_serial_idcommon.UInt32Source serial ID
source_logical_idcommon.UInt8Source logical device ID
lqioptional common.UInt8Radio communication quality
supply_voltageoptional common.UInt16Not available, always None
command_idcommon.UInt8Command ID
databytesData

You can also pass a dictionary unpacked with **.

to_df()

to_df(include=None, exclude=None, verbose=True)

Converts parsed data into a pandas DataFrame.

Arguments

NameTypeDescription
includeoptional set[str]Set of columns (members) to include in the DataFrame
excludeoptional set[str]Set of columns (members) to exclude from the DataFrame
verboseboolWhether to include system information (only effective if other args are None)

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the dictionary
excludeoptional set[str]Set of keys (members) to exclude from the dictionary
verboseboolWhether to include system information (only effective if other args are None)
spreadboolWhether to split non-time-series list-like data
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
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

NameTypeDescription
includeoptional set[str]Set of keys (members) to include in the JSON
excludeoptional set[str]Set of keys (members) to exclude from the JSON
verboseboolWhether to include system information (only effective if other args are None)
spreadboolWhether to split non-time-series list-like data
indentoptional intNumber of indent spaces (None for no line breaks)
sort_keysboolWhether to sort keys

Returns

TypeValueDescription
str-Converted JSON string

model_*()

3.2.1.1.3 - mwings.serializers Module

Serializers to generate commands and data structures to handle them.
Serializers to generate commands and data structures to handle them.

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.

src/mwings/serializers/app_twelite.py

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

NameTypeDescription
commandCommandCommand data

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded data
NoneInvalid 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

NameTypeDescription
destination_logical_idcommon.UInt8Destination logical device ID
di_to_changecommon.FixedList[bool](4)Digital interfaces to change
di_statecommon.FixedList[bool](4)Digital interface states after change
pwm_to_changecommon.FixedList[bool](4)PWM interfaces to change
pwm_dutycommon.FixedList[int](4)PWM interface duty after change

You can also pass a dictionary unpacked with **.

is_valid()

is_valid()

Checks whether the command data is valid.

Arguments

None

Returns

TypeValueDescription
boolTrueValid
FalseInvalid

model_*()

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.

src/mwings/serializers/app_io.py

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

NameTypeDescription
commandCommandCommand data

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded data
NoneInvalid 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

NameTypeDescription
destination_logical_idcommon.UInt8Destination logical device ID
di_to_changecommon.FixedList[bool](12)Digital interfaces to change
di_statecommon.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

TypeValueDescription
boolTrueValid
FalseInvalid

model_*()

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.

src/mwings/serializers/app_pal_notice.py

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

NameTypeDescription
commandCommandCommand data

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded data
NoneInvalid 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

NameTypeDescription
destination_logical_idcommon.UInt8Destination logical device ID
colorcommon.AppPalNoticeColorLighting color name
blink_speedcommon.AppPalNoticeBlinkSpeedBlinking speed
brightnesscommon.UInt8Brightness
duration_in_seccommon.UInt8Total 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

TypeValueDescription
boolTrueValid
FalseInvalid

model_*()

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.

src/mwings/serializers/app_pal_notice_detailed.py

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

NameTypeDescription
commandCommandCommand data

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded data
NoneInvalid 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

NameTypeDescription
destination_logical_idcommon.UInt8Destination logical device ID
colorcommon.AppPalNoticeRGBWColorRGBW color for illumination
blink_duty_percentagecommon.UInt8Percentage of on-time during blinking
blink_period_in_seccommon.Float64Blink period in seconds
duration_in_seccommon.UInt8Total 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

TypeValueDescription
boolTrueValid
FalseInvalid

model_*()

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.

src/mwings/serializers/app_pal_notice_event.py

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

NameTypeDescription
commandCommandCommand data

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded data
NoneInvalid 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

NameTypeDescription
destination_logical_idcommon.UInt8Destination logical device ID
event_idcommon.UInt8Event ID

You can also pass a dictionary unpacked with **.

is_valid()

is_valid()

Checks whether the command data is valid.

Arguments

None

Returns

TypeValueDescription
boolTrueValid
FalseInvalid

model_*()

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.

src/mwings/serializers/app_uart_ascii.py

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

NameTypeDescription
commandCommandCommand data

Returns

TypeValueDescription
optional common.BarePacketcommon.BarePacketExpanded data
NoneInvalid 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

NameTypeDescription
destination_logical_idcommon.UInt8Destination logical device ID
command_idcommon.UInt8Command ID
databytesData

You can pass a dictionary unpacked with **.

is_valid()

is_valid()

Checks whether the command data is valid.

Arguments

None

Returns

TypeValueDescription
boolTrueValid
FalseInvalid

model_*()

3.2.1.1.4 - mwings.utils Module

mwings.utils

Contains general-purpose utility functions.

src/mwings/utils.py

ask_user()

ask_user(prompt, regex, on_error, ex_verifier=None, max_attempts=None)

Gets input from the user via the console.

Arguments

NameTypeDescription
promptstrMessage displayed in the prompt
regexstrRegular expression to validate user input
on_errorstrMessage displayed when user input is invalid
ex_verifieroptional Callable[[str], bool]Function to further validate input string beyond regex
max_attemptsoptional intNumber of retry attempts. None means unlimited

Returns

TypeValueDescription
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

TypeValueDescription
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

NameTypeDescription
character_countintLength of the ASCII representation of the byte sequence

Returns

TypeValueDescription
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

NameTypeDescription
hexvalueintNumber

Returns

TypeValueDescription
int-ASCII code of character

find_ascii()

find_ascii(port, data, timeout, debugging=False)

Waits to receive the specified ASCII string.

Arguments

NameTypeDescription
portserial.SerialSerial port
datastrASCII string
timeoutintTimeout (seconds)
debuggingboolDebug output

Returns

TypeValueDescription
boolTrueReception confirmed
boolFalseReception not confirmed

find_binary()

find_binary(port, data, timeout, debugging=False)

Waits to receive the specified byte sequence.

Arguments

NameTypeDescription
portserial.SerialSerial port
datastrByte sequence
with_terminalboolWhether to use terminal data
terminalintData to treat as terminal
timeoutintTimeout (seconds)
debuggingboolDebug output

Returns

TypeValueDescription
boolTrueReception confirmed
boolFalseReception not confirmed

flush_rx_buffer()

flush_rx_buffer(port)

Clears the receive buffer.

Arguments

NameTypeDescription
portserial.SerialSerial port

Returns

None

flush_tx_buffer()

flush_tx_buffer(port)

Clears the transmit buffer.

Arguments

NameTypeDescription
portserial.SerialSerial port

Returns

None

get_ports()

get_ports()

Retrieves a list of available serial ports.

Arguments

None

Returns

TypeValueDescription
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

NameTypeDescription
characterintASCII code of the character

Returns

TypeValueDescription
int-Numeric value

is_initialized()

is_initialized(port)

Checks whether the serial port is initialized.

Arguments

NameTypeDescription
portserial.SerialSerial port

Returns

TypeValueDescription
boolTrueInitialized
FalseNot initialized

is_readable()

is_readable(port)

Checks whether data can be read from the serial port.

Arguments

NameTypeDescription
portserial.SerialSerial port

Returns

TypeValueDescription
boolTrueData available in receive buffer
FalseNot readable

is_there_some_ports()

is_there_some_ports()

Checks whether any serial ports are available.

Arguments

None

Returns

TypeValueDescription
boolTrueSerial ports exist
FalseNone available

is_writable()

is_writable(port)

Checks whether data can be written to the serial port.

Arguments

NameTypeDescription
portserial.SerialSerial port

Returns

TypeValueDescription
boolTrueWritable
FalseNot writable

lrc8()

lrc8(data)

Calculates the 8-bit LRC.

Arguments

NameTypeDescription
databytesByte sequence to calculate

Returns

TypeValueDescription
int-LRC8 value

millis()

millis()

Gets the current system time in milliseconds.

Arguments

None

Returns

TypeValueDescription
int-System time (ms)

open_on_system()

open_on_system(path)

Opens the specified file path with the system’s default application.

Arguments

NameTypeDescription
pathPathFile path

Returns

None

write_binary()

write_binary(port, data)

Sends a byte sequence to the serial port.

Arguments

NameTypeDescription
portserial.SerialSerial port
dataintData to send
bytesSequence 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

NameTypeDescription
portserial.SerialSerial port
dataintCharacter to send
bytesString to send

Returns

None

4 - TWENET reference

Core libraries behind MWX and TWELITE Apps
Information on the TWENET library. Contains material for internal 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

4.1 - TWENETmcu - Microcontroller Library

Library supporting the basic operation of the microcontroller
Contains source code for basic microcontroller operations.

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 like PRINTF()

Technical Documentation

This section describes implementation details of TWENET and considerations for developing application programs.

4.1.1 - About Microcontrollers

About microcontrollers
Notes on the microcontroller of TWELITE GOLD.

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 functions.

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.

ParameterDescription
flagStartup specification. Please use 0 for normal use.
u32SysHzSpecifies 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.

ParameterDescription
flagStartup 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 in JN5189.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 the IRQ_Type interrupt is enabled, this function will be called. If the return value is FALSE, NVIC_ClearPendingIRQ(IRQ_Type) is executed. If it’s TRUE, 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() in cbAppColdStart(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 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 (see AppQAPI_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.

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

RAM allocation
Describes RAM allocation.

RAM Allocation

The SRAM area of TWWLIET GOLD is as follows.

BASETOP (End + 1)SIZE
SRAM110x0402_C0000x0403_000016KB
SRAM100x0402_80000x0402_C00016KB
SRAM90x0402_40000x0402_800016KB
SRAM80x0402_00000x0402_400016KB
SRAM70x0401_50000x0401_60004KB
SRAM60x0401_40000x0401_50004KB
SRAM50x0401_20000x0401_40008KB
SRAM40x0401_00000x0401_20008KB
SRAM30x0400_C0000x0401_000016KB
SRAM20x0400_80000x0400_C00016KB
SRAM10x0400_40000x0400_800016KB
SRAM00x0400_00000x0400_400016KB

TWENET defines the memory map as follows.

BASETOPSizePurposeRETBank Name
Application Use0x0400_0000Decided at compile time~64KBRequired for MMAC linkingSRAM0..3
Heap0x0401_5000
(Changeable)
0x0401_5C003KBHeap area (malloc, new)SRAM7
Unused0x0402_00000x0402_C00048KBUnused areaSRAM8, 9, 10
SRAM11
Unused0x0402_C0000x0402_F00012KBUnused areaSRAM11
Stack0x0402_F0000x0403_00004KBStack areaSRAM11

(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 the new 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; and HEAP_SIZE = 8192 - BANK7_RESERVE; in App_User_Defs.ld (placed directly in the build directory).
      • HEAP_START is the start address of the heap, and HEAP_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)
  • 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; in App_User_Defs.ld (placed directly in the build directory). You can also specify the end address, such as STACK_TOP = 0x04024000;.
    • Please check _vStackTop and __StackLimit in the map file created in the build directory.
    • This area is not retained during sleep.

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 to 0x0401_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 to 0x0401_5000 and the STACK from 0x0401_5000 to 0x0401_5FE0. (This makes BANK8..11 from 0x0402_0000 to 0x0403_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 below 0x04015fe0:
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)

About printf (Debugging, Serial Output)
This document describes 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 calls printf_() 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.

ValueDescription
0Output 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)
1This 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.
2This 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 same SDK_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, the PRINTF() 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

A library for handling microcontroller peripherals
This is a simplified C++ class for handling microcontroller peripheral procedures.

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 NameDescription
the_adcUse the Analog-to-Digital Converter (ADC)
the_gpioUse General Purpose IO (GPIO) interrupts. (The class object is not used if you don’t need interrupts)
the_i2c0Use the I2C bus. (I2C0 only)
the_ntagUse the EEPROM for NTAG
the_pwm[0..9]Use PWM0..9
the_rngRandom number generation library
the_spi1Use the SPI bus (SPI1 only)
the_wtimerUse the wake-up timer
the_wwdtUse the watchdog timer

About the Libraries

Object NameDescription
mwf_commonCommon definitions, base class definitions for peripheral objects
mwf_periph_commonCommon definitions, procedures for pin operations
mwf_periph_adcProcedures for using the ADC
mwf_periph_gintGeneral Purpose IO (GPIO) interrupts
mwf_periph_i2cUse the I2C bus. (I2C0 only)
mwf_periph_ntagUse the EEPROM for NTAG
mwf_periph_pwmUse PWM0..9
mwf_periph_rngRandom number generation library
mwf_periph_spiUse the SPI bus (SPI1 only)
mwf_periph_wtimerUse the wake-up timer
mwf_periph_wwdtUse 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 definitions
Defines common definitions and base classes for peripheral classes.

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 is false, 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, with true, 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 to twenet_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
      • ToCoNet_vInit_Warm_Pre()
        • cbAppWarmStart(FALSE) (or init_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
      • ToCoNet_vInit_Warm()
        • cbAppWarmStart(TRUE) (or setup() in mwx)
      • TWENET initialization
      • TWENET application loop

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
Defines common peripheral definitions and pin operations.

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 for param, 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 is PORT_HIGH (1), it sets the output to HIGH; if PORT_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() and retention_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).

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 supports DEFAULT_PRESCALE=6) A prescale value that determines the ADC conversion time. It sets (1ul << .prescale) to adc_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 return false until the appropriate time has passed. You can get the tick count value at the time init() was called by calling get_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 call force_periph_enabled() immediately after calling init(). 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 with temp128th >> 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 and false 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() in adc.c that comes with App_Tweline).
  • If you are using the mwx library and also mwf::the_adc, please do not perform operations on the Analogue class object (e.g., Analogue.setup()).

4.2.4 - mwf_periph_gint - GINT(GPIO)

mwf_periph_gint - GINT(GPIO)
I implement general-purpose I/O input/output settings and I/O interrupts using GINT.

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: The p_data specified in init_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)

  1. Configures the interrupt pins.
  2. Determines and updates the pin state changes (if u32mask_rising_edge and u32mask_falling_edge are 0x80000000). If a state change occurs, it calls the callback function registered with init_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); or mwf::the_gpio->set_opt_stop_int_when_changed();). After waiting for a certain period for the pin state to stabilize, call vAHI_DioInterruptReavtivate_MW(); or mwf::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.

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.

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

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.

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.

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. Values 11 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, if set_cycle(2, 10) is specified, the PWM period is fb/10 = 800kHz, and the pulse width is 2/fb = 2/8000000 = 250ns.

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 from 0 to ct_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 as ct_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, if set_duty(100) is specified, the active period is 10% of the cycle.
  • If u16duty is set to the same value as u16duty_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% with set_duty(), the waveform will be inverted. Please be careful not to mix their usage.

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 if set_invert(false) (default) is set, and HIGH if set_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() call sys_global_resource_handler<T>::init().
    • If it’s the first instance created, it calls T::global_init().
  • The destructor and on_sleep() call sys_global_resource_handler<T>::deinit().
    • If it’s the last instance to be destroyed, it calls T::global_deinit().

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 is a peripheral object that summarizes the procedures for using the chip’s built-in random number generation hardware.

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 is a class object for using the SPI bus.

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 NameDescription
pin_confSpecifies 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.
baudSpecifies 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)
modeSPISEL is specified in init().
bitsThis 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)
sselThis 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] and pin_ssel[2] should be SSEL_VOID.
    • For two devices, set pin_ssel[0] and pin_ssel[1]. pin_ssel[2] should be SSEL_VOID.
    • For three devices, set pin_ssel[0], pin_ssel[1], and pin_ssel[2].
  • To specify hardware control, use SSEL_PRIMARY or SSEL_ALT (and SSEL_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

SignalPIO NumberDescription
SCK0Clock signal
MOSI2SPIMOSI. TWELITE side is output, external SPI device side is input.
MISO5SPIMISO. TWELITE side is input, external SPI device side is output.

Select Pins

pin_sselE_PIN_SSELPIORemarks
SSEL0 pin_ssel[0]SSEL_PRIMARY3
SSEL_ALT16
SSEL0_PIO33Software-controlled
SSEL0_PIO1616Software-controlled
SSEL1 pin_ssel[1]SSEL_PRIMARY4
SSEL_ALT14
SSEL1_PIO44Software-controlled
SSEL1_PIO1414Software-controlled
SSEL1_PIO1616Software-controlled (Cannot specify SSEL0_PIO16)
SSEL_VOIDOnly use SSEL0 for selection
SSEL2 pin_ssel[2]SSEL_PRIMARY13
SSEL2_PIO1313Software-controlled
SSEL2_PIO1717Software-controlled
SSEL_VOIDOnly use SSEL0 and SSEL1 for selection
  • A maximum of three select pins can be set in order from SSEL0 to SSEL1 and SSEL2.
  • 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

SignalPIO NumberDescription
SCK15Clock signal
MOSI17SPIMOSI. TWELITE side is output, external SPI device side is input.
MISO18SPIMISO. TWELITE side is input, external SPI device side is output.

Select Pins

pin_sselE_PIN_SSELPIORemarks
SSEL0 pin_ssel[0]SSEL_PRIMARY16
SSEL_ALT3
SSEL0_PIO33Software-controlled
SSEL0_PIO1616Software-controlled
SSEL1 pin_ssel[1]SSEL_PRIMARY14SSEL0 must be specified
SSEL_ALT4
SSEL1_PIO44Software-controlled
SSEL1_PIO1414Software-controlled
SSEL_VOIDOnly use SSEL0 for selection
SSEL2 pin_ssel[2]SSEL_PRIMARY13
SSEL_ALT5Note that this is also the PRG pin.
SSEL2_PIO55Software-controlled. Note that this is also the PRG pin.
SSEL2_PIO1313Software-controlled
SSEL_VOIDOnly use SSEL0 and SSEL1 for selection
  • A maximum of three select pins can be set in order from SSEL0 to SSEL1 and SSEL2.
  • 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 - WTIMER, FRWT
This is a peripheral object that summarizes the procedures for using the wake-up timer.

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 is 0 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 or WTIMER1_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 or WTIMER1_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 or WTIMER1_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 or WTIMER1_DEVICE).
  • Setting b_enabled to true enables interrupts. If this is not specified, an interrupt will not occur even when waking up from sleep. Note that once true has been specified for a wake-up timer, you cannot disable the interrupt by specifying false.
  • 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.

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 or WTIMER1_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 or WTIMER1_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
This is a peripheral object that summarizes the procedures for using the watchdog timer.

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 is 0 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 execute deinit() and then call init() 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. While init() used 0 as a default value, the behavior of this function when 0 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
Stop Watch is used to measure very short processing times in the msec and usec domains. It uses the microcontroller’s hardware counting function.

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 and DWT 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 - utils
Other utilities.

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

A library that encapsulates general algorithms and peripheral procedures.
This library includes general algorithms and peripheral procedures.

TWENETutils - TWENET Utility

This library includes general algorithms and peripheral procedures. It corresponds to libTWENETutils.a.

4.3.1 - utils.h

Start Functions: main(), WarmMain()
Macros and functions available by including 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
Introducing the Timer library.

Timer Library

tsTimerContext

A structure for configuration used by the Timer library.

  • Clear it to 0.
  • Ensure it is statically allocated.
TypeNameExplanation
uint8u8DeviceSpecifies the timer device (E_AHI_DEVICE_TIMER0..4).
uint16u16HzSpecifies the timer frequency in Hz.
uint8u8PreScaleSets the prescaler for the 16MHz clock.
bool_tbPWMOutIf TRUE, performs PWM output.
bool_tbDisableIntIf TRUE, disables interrupts.

vTimerConfig()

Explanation

Initializes the Timer.

Arguments

TypeNameDescription
tsTimerContextpsTCThe 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

TypeNameDescription
tsTimerContextpsTCThe 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

TypeNameDescription
tsTimerContextpsTCThe 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

TypeNameDescription
tsTimerContextpsTCThe 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 library
This is a simple implementation of 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

tsFILE

A structure that defines the output destination specified by vfPrintf() and vPutChar().

Members
TypeNameDescription
uint8u8DeviceSpecifies the serial port (E_AHI_UART_0 or E_AHI_UART_1).
bool_t (*) (uint8 u8Device, uint8 u8Char)bPutCharA 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

TypeNameDescription
tsFILE*psStreamOutput destination
const char *pcFormatOutput format
Variable arguments
Supported Formats
sString
dInteger (up to 32 bits)
uUnsigned integer (up to 32 bits)
xHexadecimal. a-f are lowercase.
XHexadecimal. A-F are uppercase.
bBit 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

TypeNameDescription
tsFILE*psStreamOutput destination
uint8u8CharOutput 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

Compatibility layer for the GOLD series providing APIs compatible with the BLUE / RED series
Explanation of the TWENETcmpt library. It enables the use of some AHI functions, previously available on TWELITE BLUE/RED, on TWELITE GOLD.

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.

LinkDescription
Common & OthersMiscellaneous functions
ADCADC-related APIs
GPIOGPIO-related APIs
PWMPWM-related APIs
I2C (SMBus)I2C-related APIs
SPISPI bus
RandomRandom number generation
UARTUART-related APIs
WDTWatchdog Timer
WTIMERWake Timer, FRWT
OnChipTempOn-chip temperature sensor (ADC)

4.4.1 - AHI-Compatible Functions

Explanation of the TWENET library and the AHI compatibility layer
This section covers general topics for AHI-compatible functions and provides explanations for AHI functions not associated with any specific peripheral.

AHI-Compatible Functions

Some of the AHI functions are implemented for source-level compatibility.

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_codeTWELITE BLUE/REDTWELITE GOLD
04Mhz12Mhz
18Mhz12Mhz
216Mhz32Mhz
332Mhz48Mhz
4..ConfigurableIgnored
  • 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.

u16AHI_PowerStatus()

uint16 u16AHI_PowerStatus();

This function reports the following bitmaps:

BitDescription
bit01 when waking up from sleep
bit11 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, not PM_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 (before cbAppWarmStart(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 (after cbAppWarmStart(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

TWENET Library, AHI Functions and Explanations Related to ADCs
Explanation of the AHI functions related to ADC in the TWENET library.

ADC

Some parts related to AHI’s ADC (Analog-to-Digital Conversion) are implemented for the purpose of source code compatibility.

Overview

The hardware specifications of the ADC vary depending on the model.

TWELITE BLUETWELITE REDTWELITE GOLD
Resolution (bits)10bit10bit12bit
Full Scale2470mV2470mV3600mV
Number of Channels
(not supported by API)
44 (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

PIONotes
ADC015
ADC114Shared with DIO8
ADC216
ADC317

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 and bRefSelect 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 after vAHI_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 returns 0xffff.
  • 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 NameDescription
adc.cADC processing part (ADC value conversion adjusted for TWELITE GOLD’s range)
adc.hDefinition part
sensor_driver.cSensor processing abstraction part
sensor_driver.hDefinition 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 voltage
    • TEH_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 voltage
    • TEH_ADC_IDX_ADC_1-4: ADC1,2,3,4

4.4.3 - AHI Functions and Explanations for DIO (GPIO)

Explanations of the TWENET library and AHI functions related to DIO (GPIO)
This section provides explanations of the TWENET library and AHI functions related to DIO (GPIO).

DIO (GPIO)

Some of the AHI functions related to DIO (GPIO) are implemented for source-level compatibility.

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

DIODIOPIONotes
DIO0016
DIO1117
DIO2218
DIO3319
DIO447
DIO556
DIO668
DIO779
DIO8814Shared with ADC1
DIO9912
DIO10104
DIO11110Shared with DO0
DIO121213
DIO13131
DIO141410
DIO151511
DIO161620
DIO171721
DIO18182
DIO19193
DO0 (PROG)0Shared with DIO11
DO15
ADC214Shared with DIO8
ADC115

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. Returns 0xff if the assignment is invalid.
  • get_dio(): Returns the DIO number corresponding to the specified PIO number. Returns 0xff 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 to 0 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 and u32Falling, 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 to 0.

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 in u8Off 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 to false, it runs at the very early stage of the WarmMain() process to identify the wake-up sources.
  • It is then called again with true just before the call to cbAppWarmStart(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() and vAHI_DioOnWakeup_MW().
      • These two functions are called from vAHI_OnSleep_MW() and vAHI_OnWakeup_MW() in TWENETcmpt.
    • 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 inside ToCoNet_vSleep() to execute sleep properly.
    • vAHI_OnWakeup_MW() and vAHI_DioOnWakeup_MW() are called within the TWENETmcu library source. Modify the processing as needed.

4.4.4 - AHI Functions and Explanations for Timer (PWM)

Explanations of the TWENET library and AHI functions related to Timer (PWM)
This section provides explanations of the TWENET library and AHI functions related to Timer (PWM).

Timer (PWM)

Some parts of the AHI Timer-related APIs are implemented for source code compatibility.

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 by bOutputEnable in vAHI_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 as bIntPeriodEnable == TRUE.
  • Even if bOutputEnable == TRUE is set, if the pin is disabled by vAHI_TimerFineGrainDIOControl(), it is treated as FALSE.
  • 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 ID01234
SMD PIN##1216131519
AHI DIO##1011121317
PIO##4013121
PWM channel40219

When Using DO1,2 in Standard Mode

AHI TIMER ID01234
SMD PIN##12161219
AHI DIO##1011DO0DO117
PIO##400521
PWM channel400N/A9
  • TIMER_1 and TIMER_2 assignments conflict.
  • The output pin for TIMER_3 does not have hardware timer functionality.

Secondary Assignment

AHI TIMER ID01234
SMD PIN##678910
AHI DIO##45678
PIO##768914
PWM channel76891

When Using DO1,2 in Secondary Assignment

AHI TIMER ID01234
SMD PIN##671910
AHI DIO##45DO0DO18
PIO##760514
PWM channel760N/A1
  • 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.
  • Define PWM0_IRQHandler()PWM9_IRQHandler() separately. Since these are specified with weak 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.
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

Explanations of the TWENET library: SMBUS (I2C)-related procedures defined in SMBus.c,h
This section provides explanations of the TWENET library and the SMBUS (I2C)-related procedures defined in SMBus.c and SMBus.h.

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 and u32clk <= 255 ⇒ Initializes with clock frequency 3200000ul / (u32clk + 1). For example, specifying 31 gives 100 kHz, and 7 gives 400 kHz.
  • If u32clk >= 12500 and u32clk <= 400000 ⇒ Initializes with u32clk 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. If 0, only the command byte is transferred. If greater than 0, 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.
    If vSMBusDeInit() is not called, the pin state is undefined (or follows the JN516x peripheral specification).
    You can reinitialize by calling vSMBusInit() or vSMBusInit_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

Explanations of the TWENET library and AHI functions related to SPI
This section provides explanations of the TWENET library and AHI functions related to SPI.

SPI

This section covers the implementation of AHI-compatible functions for SPI.

The following pins are used for SPI operation:

SignalPin Name (PIO No.)Description
SCKSPLCLK=DIO11(PIO0)Clock signal
This pin is shared with SPICLK and DIO11
MOSIDIO18(PIO2)SPIMOSI. Output from TWELITE side, input to external SPI device.
MISOSPIMISO(PIO5)SPIMISO. Input to TWELITE side, output from external SPI device.
SEL0DIO19(PIO3)
SEL1DIO0(PIO16)
SEL2DIO1(PIO17)

When using alternate pin assignments (set via vAHI_SpiSetLocation_MW(FALSE)):

SignalPin Name (PIO No.)Description
SCKADC1(PIO15)Clock signal
MOSIDIO1(PIO17)SPIMOSI. Output from TWELITE side, input to external SPI device.
MISODIO2(PIO18)SPIMISO. Input to TWELITE side, output from external SPI device.
SEL0DIO0(PIO16)
SEL1DIO8=ADC2(PIO14)This pin is shared with DIO8 and ADC2
SEL2DIO12(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 in vAHI_SpiConfigure() is set to TRUE, specifies the pin to control but does not control it at the time of this call.
  • If bAutoSlaveSelect in vAHI_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

Explanations of the TWENET library and AHI functions related to random numbers
This section provides explanations of the TWENET library and AHI functions related to random numbers.

Random (Random Numbers)

Implementation of AHI-compatible functions related to random number generation.

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

Explanations of the TWENET library and AHI functions related to UART
This section provides explanations of the TWENET library and AHI functions related to 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() or vAHI_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().
bSelTXRX
FALSEDIO14(PIO10)DIO15(PIO11)
TRUEDIO11(PIO0)*1DIO13(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)

Explanations of the TWENET library and AHI functions related to WatchDog (WDT)
This section provides explanations of the TWENET library and AHI functions related to 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 is 8 ms; otherwise, it is set as ((1UL << (u8Prescale - 1)) + 1) * 8 ms, passed to the_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

Explanations of the TWENET library and AHI functions related to WakeTimer

WakeTimer

Implementation of vAHI_WakeTimer-related compatible functions.

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 is 0x0FFFFFFF when calculating time differences.
    For example, to compute elapsed counts between ct1 and ct2, 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_0E_AHI_WAKE_TIMER_MASK_0 (1)
E_AHI_WAKE_TIMER_1E_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, returns E_AHI_WAKE_TIMER_MASK_0 (1).
  • For E_AHI_WAKE_TIMER_1, returns E_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 either NULL or a pointer to a uint32 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

Explanations of the TWENET library and AHI functions related to the 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).

SettingDescriptionNotes
0Do not automatically acquire the temperature sensor value.MAC layer temperature correction uses a fixed value (20°C).
1Automatically acquire the temperature sensor value.
uint8_t G_TWENET_CHIPSENSOR_ADC_TIMES_SCALER()
// Macro for variable access
SettingADC Count
01
12
24
38

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 an int32 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 of G_TWENET_CHIPSENSOR_ADC_TIMES_SCALER().
  • If bTurnOnSensor is set to TRUE, the function powers on the temperature sensor and performs the required waiting process. If set to FALSE, you must call vAHI_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

Implementation of C++ STL with static memory allocation
Additional explanation about the 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 calling vsnprintf_() in the printf.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

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

A library that supports interactive mode settings
This section explains the 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 library
Explanation of printf-equivalent functions.

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() Command Explanation (for internal developers)
This section explains the commands for TWESTG_CMD_u32CmdOp().

TWESTG_CMD_u32CmdOp() Command Explanation (for Internal Developers)

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 the 0x80000000 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.

ParameterTypeDescription
u8Opuint8Specifies the processing content.
pBufInTWE_tsBuffer *Input sequence.
pBufOutTWE_tsBuffer *Specifies the storage area for output data. NULL can be specified for some processes. The state on processing failure is undefined in principle.
psFinalTWESTG_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 ValueValueStatus
TWE_APIRET_SUCCESSb0..b7 → u8Op, others depend on processingOn success
TWE_APIRET_FAILb0..b7 → u8Op, others depend on processingOn 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 ColumnData TypeValueContent
[0]OCTET0x01Get module’s SID.
OtherUndefined
Subsequent data is undefined
Output Column ([0] == 0x01)Data TypeValueContent
[0..3]BE_DWORDModule’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 ColumnData TypeValueContent
[0]OCTET0x01Change the setting specified by ID.
[1]OCTETNot 0x00Setting ID
[2..]Data type dependent
Configuration Data
Setting IDContentInput DataRemarks
0x01Application IDBE_DWORD (uint32_t)
0x02Logical ID (8bit)OCTET (uint8_t)
0x03ChannelOCTET (uint8_t)
0x04Multiple ChannelsBE_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
0x05Radio Output and RetransmissionOCTET (uint8_t)Upper 4 bits: retransmission count, Lower 4 bits: output setting (0..3, 3 is highest output)
0x06, 0x08, 0x09, 0x0AOption (32bit)BE_DWORD (uint32_t)
0x07UART SettingsBE_WORD (int16_t)Input configuration data in internal format as-is.
BE_DWORDSpecifies baud rate (9600 … 250000). Other communication conditions are 8N1.
BE_DWORD OCTET OCTET OCTETSpecifies 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 ColumnData TypeValueContent
[0]OCTET0x01(QTYP) Get the setting specified by ID.
[1]OCTETNot 0x00Setting ID
Output for QTYP==1
Remarks
[0]OCTETData 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 IDContentInput DataRemarks
0x01Application IDBE_DWORD (uint32_t)
0x02Logical ID (8bit)OCTET (uint8_t)
0x03ChannelOCTET (uint8_t)
0x04Multiple ChannelsBE_WORD(uint16_t)b0: ch11, b1: ch12, …, b15: ch16
0x05Radio Output and RetransmissionOCTET (uint8_t)Upper 4 bits: retransmission count, Lower 4 bits: output setting (0..3, 3 is highest output)
0x06, 0x08, 0x09, 0x0AOption (32bit)BE_DWORD (uint32_t)
0x07UART SettingsBE_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). The TRUE specified in the third argument means that the saved configuration information is not loaded. Ensure that the application’s TWEINTRCT_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.