Feedback
Feedback

If you are having issues with the exercises, please create a ticket on DevZone: devzone.nordicsemi.com
Click or drag files to this area to upload. You can upload up to 2 files.

Target Wake Time

The main power saving feature introduced in Wi-Fi 6 is Target Wake Time (TWT), which allows devices to spend more time in sleep mode and receive data more deterministically, thereby further reducing power consumption. So how does this feature actually work and how is it different from traditional power saving in Wi-Fi? 

With the introduction of TWT, Wi-Fi devices can individually negotiate when and how frequently to wake up with the AP. Wi-Fi devices can either negotiate their own TWT agreement, or be member of a TWT Broadcast session already existing on the AP. And devices are only required to wake up for the TWT Broadcast sessions that the device belongs to. Additionally, the length of time that a device is permitted to sleep is significantly increased. In theory, a Wi-Fi 6 device can sleep for years without waking up.  

TWT is expected to work in alignment with the application running on the device. This means the application should predict the traffic, and make sure that it can be blind to the network for the period for which it is sleeping.  

It is also worth mentioning that an AP also usually has limitations on how long it will store buffered messages before they are dropped. This is not dictated by the Wi-Fi specification, but is usually implemented for practicality. If there is a lot of incoming data, and the device is sleeping for extended period, the AP may drop some of the frames. Ideally, applications should not expect incoming data when sleeping in TWT sessions. It is intended for applications that mainly have predictable uplink and downlink data, and not applications that require the device to be responsive to network notifications.  

See Operating in power save modes for more information on power saving on the nRF70 Series. 

API for Target Wake Time

Create a TWT request

TWT setup request

Create a network interface structure with struct net_if, and get the default network interface with net_if_get_default().

struct net_if *iface = net_if_get_default();

Create a struct for the Wi-Fi TWT request of type struct wifi_twt_params, which contains all the data needed when doing a TWT request.

struct wifi_twt_params params = { 0 };

params.operation = WIFI_TWT_SETUP;
params.negotiation_type = WIFI_TWT_INDIVIDUAL;
params.setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
params.dialog_token = 1;
params.flow_id = twt_flow_id;
params.setup.responder = 0;
params.setup.trigger = 0;
params.setup.implicit = 1;
params.setup.announce = 0;
params.setup.twt_wake_interval = 65000;
params.setup.twt_interval = 5000000;
  • operation: TWT operation (setup or teardown).
  • negotiation_type: TWT negotiation type (individual, broadcast, wake TBTT).
  • setup_cmd: TWT setup command (request, suggest, demand, grouping, accept, alternate, dictate, reject).
  • dialog_token: Dialog token, used to map requests to responses.
  • flow_id: Flow ID, used to map setup with teardown.
  • setup.responder: Requester (0) or responder (1). The TWT requester is the device that requests a TWT agreement with another device, in this case the AP. The responder is the device that receives and accepts the TWT request from another device.
  • setup.trigger: Trigger enabled (1) or disabled (0). When enabled, the device will send a PS-Poll (Power Save-Poll) frame to the AP at the start of the TWT service period to retrieve any buffered frames from the AP.
  • setup.implicit: Implicit (1) or explicit (0). With implicit the STA will determine the start time of the next TWT service period based on the TWT wake interval and the start time of the current TWT service period. When using explicit TWT the AP will inform the device of the start value of the next TWT service period.
  • setup.announce: Announced (1) or unannounced (0). When using announced TWT, the device sends a poll or trigger at the beginning of the TWT service period to inform the AP that it is ready to receive data. With unannounced, the AP can start transmitting data to the device within the TWT service period without first receiving a frame from the device.
  • setup.twt_wake_interval: Wake up time, how long the device is awake during each wake up.
  • setup.twt_interval: Total TWT interval (interval = wake up time + sleeping time).

When the TWT request is populated, we will send it using the API call net_mgmt() with NET_REQUEST_WIFI_TWT as request type.

net_mgmt(NET_REQUEST_WIFI_TWT, iface, &params, sizeof(params));
net_mgmt_request signature
  • mgmt_request: The request type of the Net MGMT request
  • iface: Pointer to the network interface
  • data: Pointer to data parameters of the Net MGMT request
  • len: Length of the data parameters

TWT teardown request

Get the network interface same as with TWT setup.

struct net_if *iface = net_if_get_first_wifi();

Create a parameter for the Wi-Fi TWT teardown request of type struct wifi_twt_params.

struct wifi_twt_params params = { 0 };

params.operation = WIFI_TWT_TEARDOWN;
params.negotiation_type = WIFI_TWT_INDIVIDUAL;
params.setup_cmd = WIFI_TWT_TEARDOWN;
params.dialog_token = 1;
params.flow_id = twt_flow_id;

When the TWT request is populated, we will send it using the API call net_mgmt() with NET_REQUEST_WIFI_TWT as request type.

Define the TWT event callback function

We will define the event handler twt_mgmt_event_handler() for TWT events, specifically NET_EVENT_WIFI_TWT. Upon a TWT event, we will call handle_wifi_twt_event() to handle the response.

Note that if we were using the Wi-Fi related network events defined in the Wi-Fi Management API (for example NET_EVENT_WIFI_CONNECT_RESULT), we could add the TWT events directly to our existing event handler net_mgmt_event_handler(). However, since we are using NET_EVENT_L4 connected, which has a different base, we need to define a separate event handler for the TWT events.

static void twt_mgmt_event_handler(struct net_mgmt_event_callback *cb,
			  uint32_t mgmt_event, struct net_if *iface)
{
	switch (mgmt_event) {
	case NET_EVENT_WIFI_TWT:
		handle_wifi_twt_event(cb);
		break;
	}
}

The TWT response information is given by a struct of type wifi_twt_params, which is the same as for TWT requests. The important parameters of the response are

  • operation: TWT setup or teardown
  • resp_status: Response status for a TWT request, received or not received response
  • setup_cmd: Setup commands, parameters accepted, rejected or changed by AP
  • flow_id: Used to map setup with teardown.

If the operation field is TWT teardown, this means that the AP initiated a TWT teardown and the device should disable TWT for the corresponding flow ID.

In the following event callback, we check if the TWT event was a TWT teardown from the AP and print to inform of the event before exiting the function. If it is not a teardown, we check if the event is for receiving a response. If so, we print the setup command to inform whether the request was accepted or rejected, or if parameters were changed by the AP, before we print the negotiated TWT parameters.

static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb)
{
	const struct wifi_twt_params *resp = (const struct wifi_twt_params *)cb->info;

	if (resp->operation == WIFI_TWT_TEARDOWN) {
		LOG_INF("TWT teardown received for flow ID %d\n",
		      resp->flow_id);
		return;
	}

	if (resp->resp_status == WIFI_TWT_RESP_RECEIVED) {
		LOG_INF("TWT response: %s",
		      wifi_twt_setup_cmd_txt(resp->setup_cmd));
		
		LOG_INF("== TWT negotiated parameters ==");
		LOG_INF("TWT Dialog token: %d",
		      resp->dialog_token);
		LOG_INF("TWT flow ID: %d",
		      resp->flow_id);
		LOG_INF("TWT negotiation type: %s",
		      wifi_twt_negotiation_type_txt(resp->negotiation_type));
		LOG_INF("TWT responder: %s",
		       resp->setup.responder ? "true" : "false");
		LOG_INF("TWT implicit: %s",
		      resp->setup.implicit ? "true" : "false");
		LOG_INF("TWT announce: %s",
		      resp->setup.announce ? "true" : "false");
		LOG_INF("TWT trigger: %s",
		      resp->setup.trigger ? "true" : "false");
		LOG_INF("TWT wake interval: %d us",
		      resp->setup.twt_wake_interval);
		LOG_INF("TWT interval: %lld us",
		      resp->setup.twt_interval);
		LOG_INF("========================");
	} else {
		LOG_INF("TWT response timed out\n");
	}
}

Subscribe to TWT sleep state notifications

The event NET_EVENT_WIFI_TWT_SLEEP_STATE allows us to be notified in the application layer when the sleep state of the device changes to awake or sleeping while TWT is enabled.

Add the NET_EVENT_WIFI_TWT_SLEEP_STATE event to the callback function twt_mgmt_event_handler().

The callback information provides us with information on the sleep state. In the following code, we print the current sleep state and call a function called send_packet() to send a packet when the device is awake.

case NET_EVENT_WIFI_TWT_SLEEP_STATE:
	int *twt_state;
	twt_state = (int *)(cb->info);
	LOG_INF("TWT sleep state: %s", *twt_state ? "awake" : "sleeping" );
	if (*twt_state == WIFI_TWT_STATE_AWAKE) {
		send_packet()
	}
	break;
Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.