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

BRD_ARIA

Sample using TWELITE ARIA
    TWELITE ARIA - Using Twilight ARIA to acquire sensor values.

    Act Features

    • Using TWELITE ARIA - Twilight ARIA to acquire sensor values.
    • Using sleep function for operation with coin battery.

    How to Use the Act

    Required TWELITE

    RoleExample
    ParentMONOSTICK BLUE / RED
    Run act Parent_MONOSTICK.
    ChildTWELITE ARIA BLUE / RED

    Explanation of the Act

    Include

    #include <TWELITE>
    #include <NWK_SIMPLE>// Network support
    #include <ARIA>   // TWELITE ARIA
    #include <STG_STD>   // Interactive mode
    #include <SM_SIMPLE> // Simple state machine
    

    Include the board behavior of TWELITE ARIA <ARIA>.

    setup()

    void setup(){
    	/*** SETUP section */
    	/// init vars or objects
    	step.setup(); // initialize state machine
    
    	/// load board and settings objects
    	auto&& brd = the_twelite.board.use<ARIA>(); // load board support
    	auto&& set = the_twelite.settings.use<STG_STD>(); // load save/load settings(interactive mode) support
    	auto&& nwk = the_twelite.network.use<NWK_SIMPLE>(); // load network support
    
    	/// configure settings
    	// configure settings
    	set << SETTINGS::appname("ARIA");
    	set << SETTINGS::appid_default(DEFAULT_APP_ID); // set default appID
    	set << SETTINGS::ch_default(DEFAULT_CHANNEL); // set default channel
    	set.hide_items(E_STGSTD_SETID::OPT_DWORD2, E_STGSTD_SETID::OPT_DWORD3, E_STGSTD_SETID::OPT_DWORD4, E_STGSTD_SETID::ENC_KEY_STRING, E_STGSTD_SETID::ENC_MODE);
    
    	// if SET=LOW is detected, start with interactive mode.
    	if (digitalRead(brd.PIN_SET) == PIN_STATE::LOW) {
    		set << SETTINGS::open_at_start();
    		step.next(STATE::INTERACTIVE);
    		return;
    	}
    
    	// load values
    	set.reload(); // load from EEPROM.
    	OPT_BITS = set.u32opt1(); // this value is not used in this example.
    
    	LID = set.u8devid(); // set logical ID
    
    	/// configure system basics
    	the_twelite << set; // apply settings (from interactive mode)
    
    	/// configure network
    	nwk << set; // apply settings (from interactive mode)
    	nwk << NWK_SIMPLE::logical_id(LID); // set LID again (LID can also be configured by DIP-SW.)
    
    	/// configure hardware
    	// LED setup (use periph_led_timer, which will re-start on wakeup() automatically)
    	brd.set_led(LED_TIMER::BLINK, 10); // blink (on 10ms/ off 10ms)
    
    	// let the TWELITE begin!
    	the_twelite.begin();
    
    	/*** INIT message */
    	Serial << "--- ARIA:" << FOURCHARS << " ---" << mwx::crlf;
    	Serial	<< format("-- app:x%08x/ch:%d/lid:%d"
    					, the_twelite.get_appid()
    					, the_twelite.get_channel()
    					, nwk.get_config().u8Lid
    				)
    			<< mwx::crlf;
    	Serial 	<< format("-- pw:%d/retry:%d/opt:x%08x"
    					, the_twelite.get_tx_power()
    					, nwk.get_config().u8RetryDefault
    					, OPT_BITS
    			)
    			<< mwx::crlf;
    }

    First, initialize variables and others. Here, the state machine step is initialized.

    First, register the board support <ARIA>. Sensor and DIO initialization is performed during board support initialization.

    auto&& brd = the_twelite.board.use<ARIA>();

    Next, initialize and load the interactive mode related settings.

    // configure settings
    set << SETTINGS::appname("ARIA");
    set << SETTINGS::appid_default(DEFAULT_APP_ID); // set default appID
    set << SETTINGS::ch_default(DEFAULT_CHANNEL); // set default channel
    set.hide_items(E_STGSTD_SETID::OPT_DWORD2, E_STGSTD_SETID::OPT_DWORD3, E_STGSTD_SETID::OPT_DWORD4, E_STGSTD_SETID::ENC_KEY_STRING, E_STGSTD_SETID::ENC_MODE);
    
    // if SET=LOW is detected, start with interactive mode.
    if (digitalRead(brd.PIN_SET) == PIN_STATE::LOW) {
    	set << SETTINGS::open_at_start();
    	step.next(STATE::INTERACTIVE);
    	return;
    }
    
    // load values
    set.reload(); // load from EEPROM.
    OPT_BITS = set.u32opt1(); // this value is not used in this example.
    
    LID = set.u8devid(); // set logical ID
    

    Here, the set object is obtained, the application name is reflected, default application ID and communication channel are set, and unnecessary items in the settings menu are removed.

    Next, read the state of the SET pin. Since this sample performs intermittent operation by sleep, transition to interactive mode by inputting +++ is not possible. Instead, it transitions to interactive mode when SET pin = LOW at startup. At this time, SETTINGS::open_at_start() is specified, which means to immediately transition to the interactive mode screen after setup() ends.

    Finally, .reload() is executed to read the settings from EEPROM. The setting values are copied to each variable.

    This act mainly transmits wireless packets, so the TWENET setting does not include the specification to open the receiver circuit during operation (TWENET::rx_when_idle()).

    the_twelite << set; // apply settings (from interactive mode)
    

    Next, set up the LED. Here, it is set to blink ON/OFF every 10ms (in applications with short wake-up time due to sleep, this setting is almost the same as lighting during wake-up).

    brd.set_led(LED_TIMER::BLINK, 10); // blink (on 10ms/ off 10ms)
    

    loop()

    void loop() {
    	auto&& brd = the_twelite.board.use<ARIA>();
    
    	do {
    		switch (step.state()) {
    		 // Behavior of each state
    		case STATE::INIT:
    		...
    		break;
    		...
    		}
    	while(step.b_more_loop());
    }

    loop() controls using the SM_SIMPLE state machine step. This is to concisely express the sequence from waking from sleep, acquiring sensor values, transmitting wireless packets, waiting for transmission completion, and sleeping. The brd object is obtained at the start of the loop.

    case STATE::INTERACTIVE:

    Since it is inconvenient for the main loop to operate during interactive mode, it stays fixed in this state.

    case STATE::INIT:

    brd.sns_SHT4x.begin();
    
    step.next(STATE::SENSOR);

    Start sensor data acquisition.

    case STATE::SENSOR:

    //  wait until sensor capture finish
    if (!brd.sns_SHT4x.available()) {
    	brd.sns_SHT4x.process_ev(E_EVENT_TICK_TIMER);
    }else{ // now sensor data is ready.
    	sensor.i16temp = brd.sns_SHT4x.get_temp_cent();
    	sensor.i16humid = brd.sns_SHT4x.get_humid_per_dmil();
    
    	// read magnet sensor
    	sensor.b_north = digitalRead(ARIA::PIN_SNS_NORTH);
    	sensor.b_south = digitalRead(ARIA::PIN_SNS_SOUTH);
    
    	Serial << "..finish sensor capture." << mwx::crlf
    		<< "  MAGnet   : north=" << int(sensor.b_north) << mwx::crlf
    		<< "             south=" << int(sensor.b_south) << mwx::crlf
    		<< "  SHT4x    : temp=" << div100(sensor.i16temp) << 'C' << mwx::crlf
    		<< "             humd=" << div100(sensor.i16humid) << '%' << mwx::crlf
    		;
    	Serial.flush();
    
    	step.next(STATE::TX);
    }

    The sensor on the board can be accessed by the name .sns_SHT4x, and this object is operated. Wait for sensor completion. If the sensor acquisition is not yet finished (.available() is false), send a time elapsed event (.process_ev(E_EVENT_TICK_TIMER)) to the sensor.

    When the sensor becomes available, acquire sensor values and transition to STATE_TX.

    Temperature and humidity sensor values can be obtained as follows:

    • .get_temp_cent() : int16_t : temperature with 1°C = 100 (e.g., 25.6°C is 2560)
    • .get_temp() : float : float value (e.g., 25.6°C)
    • .get_humid_dmil() : int16_t : humidity with 1% = 100 (e.g., 56.8% is 5680)
    • .get_temp() : float : float value (e.g., 56.8%)

    case STATE::TX:

    The transmission procedure is the same as other act samples. Here, it is set to retry once with minimum retry delay.

    pkt << tx_addr(0x00)  // to parent 0x00
    	<< tx_retry(0x1)    // retry once
    	<< tx_packet_delay(0, 0, 2); // minimum delay
    

    Place the identifier FOURCHARS and sensor data in the packet payload. The temperature value among the obtained values is int16_t, but since the data structure of the transmission packet stores unsigned data, it is cast to uint16_t.

    pack_bytes(pkt.get_payload() // set payload data objects.
    	, make_pair(FOURCHARS, 4)  // just to see packet identification, you can design in any.
    	, uint8_t(sensor.b_north)
    	, uint8_t(sensor.b_south)
    	, uint16_t(sensor.i16temp)
    	, uint16_t(sensor.i16humid)
    );

    Request transmission. If the request succeeds, prepare for transmission completion wait. To wait for the completion event, .clear_flag() is called and a timeout of 100 milliseconds is set with set_timeout(100).

    // do transmit
    MWX_APIRET ret = pkt.transmit();
    
    if (ret) {
    	step.clear_flag(); // waiting for flag is set.
    	step.set_timeout(100); // set timeout
    	step.next(STATE::TX_WAIT_COMP);
    }

    case STATE::TX_WAIT_COMP:

    Here, timeout judgment and transmission completion event judgment are performed.

    if (step.is_timeout()) { // maybe fatal error.
    	the_twelite.reset_system();
    }
    if (step.is_flag_ready()) { // when tx is performed
    	Serial << "..transmit complete." << mwx::crlf;
    	Serial.flush();
    	step.next(STATE::GO_SLEEP);
    }

    STATE::GO_SLEEP:

    Perform sleepNow() processing.

    on_tx_comp()

    void on_tx_comp(mwx::packet_ev_tx& ev, bool_t &b_handled) {
    	step.set_flag(ev.bStatus);
    }

    System event called at transmission completion. Here, completion is indicated by .set_flag().

    sleepNow()

    Summarize the procedure to enter sleep.

    void sleepNow() {
    	step.on_sleep(false); // reset state machine.
    
    	// randomize sleep duration.
    	uint32_t u32ct = 1750 + random(0,500);
    
    	// set an interrupt for MAGnet sensor.
    	pinMode(ARIA::PIN_SNS_OUT1, PIN_MODE::WAKE_FALLING);
    	pinMode(ARIA::PIN_SNS_OUT2, PIN_MODE::WAKE_FALLING);
    
    	// output message
    	Serial << "..sleeping " << int(u32ct) << "ms." << mwx::crlf;
    	Serial.flush(); // wait until all message printed.
    
    	// do sleep.
    	the_twelite.sleep(u32ct);
    }

    Before sleep, reset the state machine by .on_sleep(false). The parameter false means to start from STATE::INIT(=0) after waking from sleep.

    Here, the wake-up time is randomized between 1750ms and 2250ms. This avoids continuous collisions with packets of other devices transmitting with the same cycle.

    Lines 8 and 9 set interrupt for the magnet sensor’s DIO pins before entering sleep using pinMode(). The second parameter is set to PIN_MODE::WAKE_FALLING, which wakes up when the pin state changes from HIGH to LOW.

    Lines 12 and 13 wait for serial port output before sleeping. Usually, to minimize power consumption, serial port output before sleep is minimized or omitted.

    Line 16 calls the_twelite.sleep() to enter sleep. This call performs pre-sleep procedures on board hardware, such as turning off LEDs.

    The parameter specifies sleep duration in milliseconds.

    wakeup()

    wakeup() is called when waking from sleep. After that, loop() is called repeatedly. Before wakeup(), peripherals such as UART and devices on the board perform wake-up processing. For example, LED lighting control restarts.

    void wakeup() {
        Serial	<< mwx::crlf
            	<< "--- ARIA:" << FOURCHARS << " wake up ";
    
        if (the_twelite.is_wokeup_by_wktimer()) {
            Serial << "(WakeTimer) ---";
        } else
        if (the_twelite.is_wokeup_by_dio(ARIA::PIN_SNS_NORTH)) {
            Serial << "(MAGnet INT [N]) ---";
        } else
        if (the_twelite.is_wokeup_by_dio(ARIA::PIN_SNS_SOUTH)) {
            Serial << "(MAGnet INT [S]) ---";
        } else {
            Serial << "(unknown source) ---";
        }
    
    	Serial  << mwx::crlf
    			<< "..start sensor capture again."
    			<< mwx::crlf;
    }