for (i = 0; i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); i++)
rate_scope->ht_mcs_rate_bitmap[i] = cpu_to_le16(pbitmap_rates[2 + i]);
if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { for (i = 0; i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap); i++)
rate_scope->vht_mcs_rate_bitmap[i] =
cpu_to_le16(pbitmap_rates[10 + i]);
}
/* * This function prepares command to stop Ad-Hoc network. * * Preparation includes - * - Setting command ID and proper size * - Ensuring correct endian-ness
*/ staticint mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd)
{
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
cmd->size = cpu_to_le16(S_DS_GEN); return0;
}
/* * This function sets WEP key(s) to key parameter TLV(s). * * Multi-key parameter TLVs are supported, so we can send multiple * WEP keys in a single buffer.
*/ staticint
mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, struct mwifiex_ie_type_key_param_set *key_param_set,
u16 *key_param_len)
{ int cur_key_param_len;
u8 i;
/* Multi-key_param_set TLV is supported */ for (i = 0; i < NUM_WEP_KEYS; i++) { if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
(priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
key_param_set->type =
cpu_to_le16(TLV_TYPE_KEY_MATERIAL); /* Key_param_set WEP fixed length */ #define KEYPARAMSET_WEP_FIXED_LEN 8
key_param_set->length = cpu_to_le16((u16)
(priv->wep_key[i].
key_length +
KEYPARAMSET_WEP_FIXED_LEN));
key_param_set->key_type_id =
cpu_to_le16(KEY_TYPE_ID_WEP);
key_param_set->key_info =
cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
KEY_MCAST);
key_param_set->key_len =
cpu_to_le16(priv->wep_key[i].key_length); /* Set WEP key index */
key_param_set->key[0] = i; /* Set default Tx key flag */ if (i ==
(priv->
wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
key_param_set->key[1] = 1; else
key_param_set->key[1] = 0;
memmove(&key_param_set->key[2],
priv->wep_key[i].key_material,
priv->wep_key[i].key_length);
/* * This function prepares command to set/get register value. * * Preparation includes - * - Setting command ID, action and proper size * - Setting register offset (for both GET and SET) and * register value (for SET only) * - Ensuring correct endian-ness * * The following type of registers can be accessed with this function - * - MAC register * - BBP register * - RF register * - PMIC register * - CAU register * - EEPROM
*/ staticint mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
u16 cmd_action, void *data_buf)
{ struct mwifiex_ds_reg_rw *reg_rw = data_buf;
switch (le16_to_cpu(cmd->command)) { case HostCmd_CMD_MAC_REG_ACCESS:
{ struct host_cmd_ds_mac_reg_access *mac_reg;
/* * This function prepares command for event subscription, configuration * and query. Events can be subscribed or unsubscribed. Current subscribed * events can be queried. Also, current subscribed events are reported in * every FW response.
*/ staticint
mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, struct mwifiex_ds_misc_subsc_evt *subsc_evt_cfg)
{ struct host_cmd_ds_802_11_subsc_evt *subsc_evt = &cmd->params.subsc_evt; struct mwifiex_ie_types_rssi_threshold *rssi_tlv;
u16 event_bitmap;
u8 *pos;
/* * Append TLV structures for each of the specified events for * subscribing or re-configuring. This is not required for * bitwise unsubscribing request.
*/ if (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) return0;
/* Total rule length is sizeof max_coalescing_delay(u16), * num_of_fields(u8), pkt_type(u8) and total length of the all * params
*/
rule->header.len = cpu_to_le16(length + sizeof(u16) + sizeof(u8) + sizeof(u8));
/* Add the rule length to the command size*/
le16_unaligned_add_cpu(&cmd->size,
le16_to_cpu(rule->header.len) + sizeof(struct mwifiex_ie_types_header));
rule = (void *)((u8 *)rule->params + length);
}
/* Add sizeof action, num_of_rules to total command length */
le16_unaligned_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16));
/* This function check if the command is supported by firmware */ staticint mwifiex_is_cmd_supported(struct mwifiex_private *priv, u16 cmd_no)
{ if (!ISSUPP_ADHOC_ENABLED(priv->adapter->fw_cap_info)) { switch (cmd_no) { case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: case HostCmd_CMD_802_11_AD_HOC_START: case HostCmd_CMD_802_11_AD_HOC_JOIN: case HostCmd_CMD_802_11_AD_HOC_STOP: return -EOPNOTSUPP; default: break;
}
}
return0;
}
/* * This function prepares the commands before sending them to the firmware. * * This is a generic function which calls specific command preparation * routines based upon the command number.
*/ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid, void *data_buf, void *cmd_buf)
{ struct host_cmd_ds_command *cmd_ptr = cmd_buf; int ret = 0;
if (mwifiex_is_cmd_supported(priv, cmd_no)) {
mwifiex_dbg(priv->adapter, ERROR, "0x%x command not supported by firmware\n",
cmd_no); return -EOPNOTSUPP;
}
/* Prepare command */ switch (cmd_no) { case HostCmd_CMD_GET_HW_SPEC:
ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); break; case HostCmd_CMD_CFG_DATA:
ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_MAC_CONTROL:
ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_802_11_MAC_ADDRESS:
ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
cmd_action); break; case HostCmd_CMD_MAC_MULTICAST_ADR:
ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_TX_RATE_CFG:
ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_TXPWR_CFG:
ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_RF_TX_PWR:
ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_RF_ANTENNA:
ret = mwifiex_cmd_rf_antenna(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_802_11_PS_MODE_ENH:
ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
(uint16_t)cmd_oid, data_buf); break; case HostCmd_CMD_802_11_HS_CFG_ENH:
ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
(struct mwifiex_hs_config_param *) data_buf); break; case HostCmd_CMD_802_11_SCAN:
ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); break; case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
ret = mwifiex_cmd_802_11_bg_scan_config(priv, cmd_ptr,
data_buf); break; case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); break; case HostCmd_CMD_802_11_ASSOCIATE:
ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_802_11_DEAUTHENTICATE:
ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
data_buf); break; case HostCmd_CMD_802_11_AD_HOC_START:
ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
data_buf); break; case HostCmd_CMD_802_11_GET_LOG:
ret = mwifiex_cmd_802_11_get_log(cmd_ptr); break; case HostCmd_CMD_802_11_AD_HOC_JOIN:
ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
data_buf); break; case HostCmd_CMD_802_11_AD_HOC_STOP:
ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr); break; case HostCmd_CMD_RSSI_INFO:
ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); break; case HostCmd_CMD_802_11_SNMP_MIB:
ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
cmd_oid, data_buf); break; case HostCmd_CMD_802_11_TX_RATE_QUERY:
cmd_ptr->command =
cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
S_DS_GEN);
priv->tx_rate = 0;
ret = 0; break; case HostCmd_CMD_VERSION_EXT:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.verext.version_str_sel =
(u8)(get_unaligned((u32 *)data_buf));
memcpy(&cmd_ptr->params, data_buf, sizeof(struct host_cmd_ds_version_ext));
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
S_DS_GEN);
ret = 0; break; case HostCmd_CMD_MGMT_FRAME_REG:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.reg_mask.action = cpu_to_le16(cmd_action);
cmd_ptr->params.reg_mask.mask = cpu_to_le32(
get_unaligned((u32 *)data_buf));
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_mgmt_frame_reg) +
S_DS_GEN);
ret = 0; break; case HostCmd_CMD_REMAIN_ON_CHAN:
cmd_ptr->command = cpu_to_le16(cmd_no);
memcpy(&cmd_ptr->params, data_buf, sizeof(struct host_cmd_ds_remain_on_chan));
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
S_DS_GEN); break; case HostCmd_CMD_11AC_CFG:
ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_PACKET_AGGR_CTRL:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.pkt_aggr_ctrl.action = cpu_to_le16(cmd_action);
cmd_ptr->params.pkt_aggr_ctrl.enable =
cpu_to_le16(*(u16 *)data_buf);
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_pkt_aggr_ctrl) +
S_DS_GEN); break; case HostCmd_CMD_P2P_MODE_CFG:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
cmd_ptr->params.mode_cfg.mode = cpu_to_le16(
get_unaligned((u16 *)data_buf));
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_p2p_mode_cfg) +
S_DS_GEN); break; case HostCmd_CMD_FUNC_INIT: if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->size = cpu_to_le16(S_DS_GEN); break; case HostCmd_CMD_FUNC_SHUTDOWN:
priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->size = cpu_to_le16(S_DS_GEN); break; case HostCmd_CMD_11N_ADDBA_REQ:
ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf); break; case HostCmd_CMD_11N_DELBA:
ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf); break; case HostCmd_CMD_11N_ADDBA_RSP:
ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_802_11_KEY_MATERIAL:
ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
cmd_action, cmd_oid,
data_buf); break; case HostCmd_CMD_802_11D_DOMAIN_INFO:
ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
cmd_action); break; case HostCmd_CMD_RECONFIGURE_TX_BUFF:
ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_AMSDU_AGGR_CTRL:
ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_11N_CFG:
ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_WMM_GET_STATUS:
mwifiex_dbg(priv->adapter, CMD, "cmd: WMM: WMM_GET_STATUS cmd sent\n");
cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
cmd_ptr->size =
cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
S_DS_GEN);
ret = 0; break; case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_802_11_SCAN_EXT:
ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_MEM_ACCESS:
ret = mwifiex_cmd_mem_access(cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_MAC_REG_ACCESS: case HostCmd_CMD_BBP_REG_ACCESS: case HostCmd_CMD_RF_REG_ACCESS: case HostCmd_CMD_PMIC_REG_ACCESS: case HostCmd_CMD_CAU_REG_ACCESS: case HostCmd_CMD_802_11_EEPROM_ACCESS:
ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_SET_BSS_MODE:
cmd_ptr->command = cpu_to_le16(cmd_no); if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
cmd_ptr->params.bss_mode.con_type =
CONNECTION_TYPE_ADHOC; elseif (priv->bss_mode == NL80211_IFTYPE_STATION ||
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT)
cmd_ptr->params.bss_mode.con_type =
CONNECTION_TYPE_INFRA; elseif (priv->bss_mode == NL80211_IFTYPE_AP ||
priv->bss_mode == NL80211_IFTYPE_P2P_GO)
cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP;
cmd_ptr->size = cpu_to_le16(sizeof(struct
host_cmd_ds_set_bss_mode) + S_DS_GEN);
ret = 0; break; case HostCmd_CMD_PCIE_DESC_DETAILS:
ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action); break; case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_MEF_CFG:
ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_COALESCE_CFG:
ret = mwifiex_cmd_coalesce_cfg(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_TDLS_CONFIG:
ret = mwifiex_cmd_tdls_config(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_CHAN_REPORT_REQUEST:
ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,
data_buf); break; case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_HS_WAKEUP_REASON:
ret = mwifiex_cmd_get_wakeup_reason(priv, cmd_ptr); break; case HostCmd_CMD_MC_POLICY:
ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_ROBUST_COEX:
ret = mwifiex_cmd_robust_coex(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG:
ret = mwifiex_cmd_gtk_rekey_offload(priv, cmd_ptr, cmd_action,
data_buf); break; case HostCmd_CMD_CHAN_REGION_CFG:
ret = mwifiex_cmd_chan_region_cfg(priv, cmd_ptr, cmd_action); break; case HostCmd_CMD_FW_DUMP_EVENT:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->size = cpu_to_le16(S_DS_GEN); break; case HostCmd_CMD_STA_CONFIGURE:
ret = mwifiex_cmd_get_chan_info(cmd_ptr, cmd_action); break; default:
mwifiex_dbg(priv->adapter, ERROR, "PREP_CMD: unknown cmd- %#x\n", cmd_no);
ret = -1; break;
} return ret;
}
/* * This function issues commands to initialize firmware. * * This is called after firmware download to bring the card to * working state. * Function is also called during reinitialization of virtual * interfaces. * * The following commands are issued sequentially - * - Set PCI-Express host buffer configuration (PCIE only) * - Function init (for first interface only) * - Read MAC address (for first interface only) * - Reconfigure Tx buffer size (for first interface only) * - Enable auto deep sleep (for first interface only) * - Get Tx rate * - Get Tx power * - Set IBSS coalescing status * - Set AMSDU aggregation control * - Set 11d control * - Set MAC control (this must be the last command to initialize firmware)
*/ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
{ struct mwifiex_adapter *adapter = priv->adapter; int ret; struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; struct mwifiex_ds_auto_ds auto_ds; enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg;
u8 sdio_sp_rx_aggr_enable;
u16 packet_aggr_enable; int data;
if (first_sta) { if (priv->adapter->iface_type == MWIFIEX_PCIE) {
ret = mwifiex_send_cmd(priv,
HostCmd_CMD_PCIE_DESC_DETAILS,
HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) return -1;
}
ret = mwifiex_send_cmd(priv, HostCmd_CMD_FUNC_INIT,
HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) return -1;
/* Download calibration data to firmware. * The cal-data can be read from device tree and/or * a configuration file and downloaded to firmware.
*/ if (adapter->dt_node) { if (of_property_read_u32(adapter->dt_node, "marvell,wakeup-pin",
&data) == 0) {
pr_debug("Wakeup pin = 0x%x\n", data);
adapter->hs_cfg.gpio = data;
}
/* get tx rate */
ret = mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG,
HostCmd_ACT_GEN_GET, 0, NULL, true); if (ret) return -1;
priv->data_rate = 0;
/* get tx power */
ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR,
HostCmd_ACT_GEN_GET, 0, NULL, true); if (ret) return -1;
memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
amsdu_aggr_ctrl.enable = true; /* Send request to firmware */
ret = mwifiex_send_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
HostCmd_ACT_GEN_SET, 0,
&amsdu_aggr_ctrl, true); if (ret) return -1; /* MAC Control must be the last command in init_fw */ /* set MAC Control */
ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
HostCmd_ACT_GEN_SET, 0,
&priv->curr_pkt_filter, true); if (ret) return -1;
if (!disable_auto_ds && first_sta &&
priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Enable auto deep sleep */
auto_ds.auto_ds = DEEP_SLEEP_ON;
auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
EN_AUTO_PS, BITMAP_AUTO_DS,
&auto_ds, true); if (ret) return -1;
}
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Send cmd to FW to enable/disable 11D function */
state_11d = ENABLE_11D;
ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11D_I,
&state_11d, true); if (ret)
mwifiex_dbg(priv->adapter, ERROR, "11D: failed to enable 11D\n");
}
/* Pacekt aggregation handshake with firmware */ if (aggr_ctrl) {
packet_aggr_enable = true;
mwifiex_send_cmd(priv, HostCmd_CMD_PACKET_AGGR_CTRL,
HostCmd_ACT_GEN_SET, 0,
&packet_aggr_enable, true);
}
/* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit
*/
tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG,
HostCmd_ACT_GEN_SET, 0, &tx_cfg, true);
return ret;
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.27Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.