A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/espressif/esp-idf/commit/871247de220bbf68e6ca491f1387e105f4988716 below:

Merge branch 'test/ctrl_acl_u_pkt_type_v5.0' into 'release/v5.0' · espressif/esp-idf@871247d · GitHub

File tree Expand file treeCollapse file tree 13 files changed

+297

-8

lines changed

Filter options

Expand file treeCollapse file tree 13 files changed

+297

-8

lines changed Original file line number Diff line number Diff line change

@@ -1,5 +1,5 @@

1 1

/*

2 -

* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD

2 +

* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD

3 3

*

4 4

* SPDX-License-Identifier: Apache-2.0

5 5

*/

@@ -424,4 +424,23 @@ esp_err_t esp_bt_gap_set_qos(esp_bd_addr_t remote_bda, uint32_t t_poll)

424 424

arg.set_qos.t_poll = t_poll;

425 425

return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);

426 426

}

427 + 428 +

esp_err_t esp_bt_gap_set_acl_pkt_types(esp_bd_addr_t remote_bda, uint16_t pkt_types)

429 +

{

430 +

btc_msg_t msg;

431 +

btc_gap_bt_args_t arg;

432 + 433 +

if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {

434 +

return ESP_ERR_INVALID_STATE;

435 +

}

436 + 437 +

msg.sig = BTC_SIG_API_CALL;

438 +

msg.pid = BTC_PID_GAP_BT;

439 +

msg.act = BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES;

440 + 441 +

memcpy(&arg.set_acl_pkt_types.bda, remote_bda, sizeof(bt_bdaddr_t));

442 +

arg.set_acl_pkt_types.pkt_types = pkt_types;

443 +

return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);

444 +

}

445 + 427 446

#endif /* #if BTC_GAP_BT_INCLUDED == TRUE */

Original file line number Diff line number Diff line change

@@ -1,5 +1,5 @@

1 1

/*

2 -

* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD

2 +

* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD

3 3

*

4 4

* SPDX-License-Identifier: Apache-2.0

5 5

*/

@@ -91,7 +91,35 @@ typedef struct {

91 91 92 92

typedef uint8_t esp_bt_eir_type_t;

93 93 94 - 94 +

/* ACL Packet Types */

95 +

#define ESP_BT_ACL_PKT_TYPES_MASK_DM1 0x0008

96 +

#define ESP_BT_ACL_PKT_TYPES_MASK_DH1 0x0010

97 +

#define ESP_BT_ACL_PKT_TYPES_MASK_DM3 0x0400

98 +

#define ESP_BT_ACL_PKT_TYPES_MASK_DH3 0x0800

99 +

#define ESP_BT_ACL_PKT_TYPES_MASK_DM5 0x4000

100 +

#define ESP_BT_ACL_PKT_TYPES_MASK_DH5 0x8000

101 +

#define ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH1 0x0002

102 +

#define ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH1 0x0004

103 +

#define ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH3 0x0100

104 +

#define ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH3 0x0200

105 +

#define ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH5 0x1000

106 +

#define ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH5 0x2000

107 + 108 +

// DM1 cann not be disabled. All options are mandatory to include DM1.

109 +

#define ESP_BT_ACL_DM1_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DM1 | 0x330e) /* 0x330e */

110 +

#define ESP_BT_ACL_DH1_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DH1 | 0x330e) /* 0x331e */

111 +

#define ESP_BT_ACL_DM3_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DM3 | 0x330e) /* 0x370e */

112 +

#define ESP_BT_ACL_DH3_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DH3 | 0x330e) /* 0x3b0e */

113 +

#define ESP_BT_ACL_DM5_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DM5 | 0x330e) /* 0x730e */

114 +

#define ESP_BT_ACL_DH5_ONLY (ESP_BT_ACL_PKT_TYPES_MASK_DH5 | 0x330e) /* 0xb30e */

115 +

#define ESP_BT_ACL_2_DH1_ONLY (~ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH1 & 0x330e) /* 0x330c */

116 +

#define ESP_BT_ACL_3_DH1_ONLY (~ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH1 & 0x330e) /* 0x330a */

117 +

#define ESP_BT_ACL_2_DH3_ONLY (~ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH3 & 0x330e) /* 0x320e */

118 +

#define ESP_BT_ACL_3_DH3_ONLY (~ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH3 & 0x330e) /* 0x310e */

119 +

#define ESP_BT_ACL_2_DH5_ONLY (~ESP_BT_ACL_PKT_TYPES_MASK_NO_2_DH5 & 0x330e) /* 0x230e */

120 +

#define ESP_BT_ACL_3_DH5_ONLY (~ESP_BT_ACL_PKT_TYPES_MASK_NO_3_DH5 & 0x330e) /* 0x130e */

121 + 122 +

typedef uint16_t esp_bt_acl_pkt_type_t;

95 123 96 124

/* ESP_BT_EIR_FLAG bit definition */

97 125

#define ESP_BT_EIR_FLAG_LIMIT_DISC (0x01 << 0)

@@ -218,6 +246,7 @@ typedef enum {

218 246

ESP_BT_GAP_QOS_CMPL_EVT, /*!< QOS complete event */

219 247

ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT, /*!< ACL connection complete status event */

220 248

ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT, /*!< ACL disconnection complete status event */

249 +

ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT, /*!< Set ACL packet types event */

221 250

ESP_BT_GAP_EVT_MAX,

222 251

} esp_bt_gap_cb_event_t;

223 252

@@ -377,6 +406,15 @@ typedef union {

377 406

logical transport. unit is 0.625ms. */

378 407

} qos_cmpl; /*!< QoS complete parameter struct */

379 408 409 +

/**

410 +

* @brief ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT

411 +

*/

412 +

struct set_acl_pkt_types_param {

413 +

esp_bt_status_t status; /*!< set ACL packet types status */

414 +

esp_bd_addr_t bda; /*!< remote bluetooth device address */

415 +

uint16_t pkt_types; /*!< packet types successfully set */

416 +

} set_acl_pkt_types; /*!< set ACL packet types parameter struct */

417 + 380 418

/**

381 419

* @brief ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT

382 420

*/

@@ -791,6 +829,17 @@ esp_err_t esp_bt_gap_read_remote_name(esp_bd_addr_t remote_bda);

791 829

*/

792 830

esp_err_t esp_bt_gap_set_qos(esp_bd_addr_t remote_bda, uint32_t t_poll);

793 831 832 +

/**

833 +

* @brief Set ACL packet types. FOR INTERNAL TESTING ONLY.

834 +

* An ESP_BT_GAP_SET_ACL_PPKT_TYPES_EVT event will reported to

835 +

* the APP layer.

836 +

*

837 +

* @return - ESP_OK: success

838 +

* - ESP_ERR_INVALID_STATE: if bluetooth stack is not yet enabled

839 +

* - other: failed

840 +

*/

841 +

esp_err_t esp_bt_gap_set_acl_pkt_types(esp_bd_addr_t remote_bda, esp_bt_acl_pkt_type_t pkt_types);

842 + 794 843

#ifdef __cplusplus

795 844

}

796 845

#endif

Original file line number Diff line number Diff line change

@@ -825,6 +825,28 @@ void bta_dm_config_eir (tBTA_DM_MSG *p_data)

825 825 826 826

bta_dm_set_eir(NULL);

827 827

}

828 + 829 +

/*******************************************************************************

830 +

**

831 +

** Function bta_dm_set_acl_pkt_types

832 +

**

833 +

** Description Sets ACL packet types

834 +

**

835 +

**

836 +

** Returns void

837 +

**

838 +

*******************************************************************************/

839 +

void bta_dm_set_acl_pkt_types (tBTA_DM_MSG *p_data)

840 +

{

841 +

if (p_data->set_acl_pkt_types.set_acl_pkt_types_cb != NULL) {

842 +

BTM_SetAclPktTypes(p_data->set_acl_pkt_types.rmt_addr,

843 +

p_data->set_acl_pkt_types.pkt_types,

844 +

p_data->set_acl_pkt_types.set_acl_pkt_types_cb);

845 +

} else {

846 +

APPL_TRACE_ERROR("%s(), the callback function can't be NULL.", __func__);

847 +

}

848 +

}

849 + 828 850

#endif

829 851

/*******************************************************************************

830 852

**

Original file line number Diff line number Diff line change

@@ -271,6 +271,30 @@ void BTA_DmSetAfhChannels(const uint8_t *channels, tBTA_CMPL_CB *set_afh_cb)

271 271

bta_sys_sendmsg(p_msg);

272 272

}

273 273

}

274 + 275 +

/*******************************************************************************

276 +

**

277 +

** Function BTA_DmSetAclPktTypes

278 +

**

279 +

** Description This function sets the packet types used for ACL traffic.

280 +

**

281 +

**

282 +

** Returns void

283 +

**

284 +

*******************************************************************************/

285 +

void BTA_DmSetAclPktTypes(BD_ADDR remote_addr, UINT16 pkt_types, tBTM_CMPL_CB *p_cb)

286 +

{

287 +

tBTA_DM_API_SET_ACL_PKT_TYPES *p_msg;

288 + 289 +

if ((p_msg = (tBTA_DM_API_SET_ACL_PKT_TYPES *) osi_malloc(sizeof(tBTA_DM_API_SET_ACL_PKT_TYPES))) != NULL) {

290 +

p_msg->hdr.event = BTA_DM_API_SET_ACL_PKT_TYPES_EVT;

291 +

bdcpy(p_msg->rmt_addr, remote_addr);

292 +

p_msg->pkt_types = pkt_types;

293 +

p_msg->set_acl_pkt_types_cb = p_cb;

294 + 295 +

bta_sys_sendmsg(p_msg);

296 +

}

297 +

}

274 298

#endif /// CLASSIC_BT_INCLUDED == TRUE

275 299 276 300

#if (SDP_INCLUDED == TRUE)

Original file line number Diff line number Diff line change

@@ -61,6 +61,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {

61 61

bta_dm_get_dev_name, /* BTA_DM_API_GET_NAME_EVT */

62 62

#if (CLASSIC_BT_INCLUDED == TRUE)

63 63

bta_dm_config_eir, /* BTA_DM_API_CONFIG_EIR_EVT */

64 +

bta_dm_set_acl_pkt_types, /* BTA_DM_API_SET_ACL_PKT_TYPES_EVT */

64 65

#endif

65 66

bta_dm_set_afh_channels, /* BTA_DM_API_SET_AFH_CHANNELS_EVT */

66 67

#if (SDP_INCLUDED == TRUE)

Original file line number Diff line number Diff line change

@@ -56,6 +56,7 @@ enum {

56 56

BTA_DM_API_GET_NAME_EVT,

57 57

#if (CLASSIC_BT_INCLUDED == TRUE)

58 58

BTA_DM_API_CONFIG_EIR_EVT,

59 +

BTA_DM_API_SET_ACL_PKT_TYPES_EVT,

59 60

#endif

60 61

BTA_DM_API_SET_AFH_CHANNELS_EVT,

61 62

#if (SDP_INCLUDED == TRUE)

@@ -267,6 +268,14 @@ typedef struct {

267 268

tBTA_CMPL_CB *set_afh_cb;

268 269

}tBTA_DM_API_SET_AFH_CHANNELS;

269 270 271 +

/* data type for BTA_DM_API_SET_ACL_PKT_TYPES_EVT */

272 +

typedef struct {

273 +

BT_HDR hdr;

274 +

BD_ADDR rmt_addr;

275 +

UINT16 pkt_types;

276 +

tBTM_CMPL_CB *set_acl_pkt_types_cb;

277 +

} tBTA_DM_API_SET_ACL_PKT_TYPES;

278 + 270 279

/* data type for BTA_DM_API_GET_REMOTE_NAME_EVT */

271 280

typedef struct {

272 281

BT_HDR hdr;

@@ -1086,6 +1095,7 @@ typedef union {

1086 1095

tBTA_DM_API_CONFIG_EIR config_eir;

1087 1096 1088 1097

tBTA_DM_API_SET_AFH_CHANNELS set_afh_channels;

1098 +

tBTA_DM_API_SET_ACL_PKT_TYPES set_acl_pkt_types;

1089 1099

#if (SDP_INCLUDED == TRUE)

1090 1100

tBTA_DM_API_GET_REMOTE_NAME get_rmt_name;

1091 1101

#endif

@@ -1587,6 +1597,7 @@ extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data);

1587 1597

extern void bta_dm_get_dev_name (tBTA_DM_MSG *p_data);

1588 1598

#if (CLASSIC_BT_INCLUDED == TRUE)

1589 1599

extern void bta_dm_config_eir (tBTA_DM_MSG *p_data);

1600 +

extern void bta_dm_set_acl_pkt_types (tBTA_DM_MSG *p_data);

1590 1601

#endif

1591 1602

extern void bta_dm_set_afh_channels (tBTA_DM_MSG *p_data);

1592 1603

extern void bta_dm_read_rmt_name(tBTA_DM_MSG *p_data);

Original file line number Diff line number Diff line change

@@ -438,6 +438,8 @@ typedef tBTM_RSSI_RESULTS tBTA_RSSI_RESULTS;

438 438

typedef tBTM_SET_AFH_CHANNELS_RESULTS tBTA_SET_AFH_CHANNELS_RESULTS;

439 439

typedef tBTM_BLE_SET_CHANNELS_RESULTS tBTA_BLE_SET_CHANNELS_RESULTS;

440 440 441 +

typedef tBTM_SET_ACL_PKT_TYPES_RESULTS tBTA_SET_ACL_PKT_TYPES_RESULTS;

442 + 441 443

typedef tBTM_REMOTE_DEV_NAME tBTA_REMOTE_DEV_NAME;

442 444 443 445

/* advertising channel map */

@@ -1762,6 +1764,18 @@ void BTA_DmSetAfhChannels(const uint8_t *channels, tBTA_CMPL_CB *set_afh_cb);

1762 1764

void BTA_DmSetQos(BD_ADDR bd_addr, UINT32 t_poll, tBTM_CMPL_CB *p_cb);

1763 1765

#endif /// (BTA_DM_QOS_INCLUDED == TRUE)

1764 1766 1767 +

/*******************************************************************************

1768 +

**

1769 +

** Function BTA_DmSetAclPktTypes

1770 +

**

1771 +

** Description This function sets the packet types used for ACL traffic.

1772 +

**

1773 +

**

1774 +

** Returns void

1775 +

**

1776 +

*******************************************************************************/

1777 +

void BTA_DmSetAclPktTypes(BD_ADDR remote_addr, UINT16 pkt_types, tBTM_CMPL_CB *p_cb);

1778 + 1765 1779

#if (BLE_INCLUDED == TRUE)

1766 1780

/*******************************************************************************

1767 1781

**

Original file line number Diff line number Diff line change

@@ -1,5 +1,5 @@

1 1

/*

2 -

* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD

2 +

* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD

3 3

*

4 4

* SPDX-License-Identifier: Apache-2.0

5 5

*/

@@ -726,6 +726,33 @@ static void btc_gap_bt_set_afh_channels(btc_gap_bt_args_t *arg)

726 726

BTA_DmSetAfhChannels(arg->set_afh_channels.channels, btc_gap_bt_set_afh_channels_cmpl_callback);

727 727

}

728 728 729 +

static void btc_gap_bt_set_acl_pkt_types_cmpl_callback(void *p_data)

730 +

{

731 +

tBTA_SET_ACL_PKT_TYPES_RESULTS *result = (tBTA_SET_ACL_PKT_TYPES_RESULTS *)p_data;

732 +

esp_bt_gap_cb_param_t param;

733 +

bt_status_t ret;

734 +

btc_msg_t msg;

735 +

msg.sig = BTC_SIG_API_CB;

736 +

msg.pid = BTC_PID_GAP_BT;

737 +

msg.act = BTC_GAP_BT_SET_ACL_PKT_TYPES_EVT;

738 + 739 +

param.set_acl_pkt_types.status = btc_btm_status_to_esp_status(result->status);

740 +

memcpy(param.set_acl_pkt_types.bda, result->rem_bda, sizeof(esp_bd_addr_t));

741 +

param.set_acl_pkt_types.pkt_types = result->pkt_types;

742 + 743 +

ret = btc_transfer_context(&msg, &param, sizeof(esp_bt_gap_cb_param_t), NULL, NULL);

744 +

if (ret != BT_STATUS_SUCCESS) {

745 +

BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);

746 +

}

747 +

}

748 + 749 +

static void btc_gap_set_acl_pkt_types(btc_gap_bt_args_t *arg)

750 +

{

751 +

BTA_DmSetAclPktTypes(arg->set_acl_pkt_types.bda.address,

752 +

arg->set_acl_pkt_types.pkt_types,

753 +

btc_gap_bt_set_acl_pkt_types_cmpl_callback);

754 +

}

755 + 729 756

static void btc_gap_bt_read_remote_name_cmpl_callback(void *p_data)

730 757

{

731 758

tBTA_REMOTE_DEV_NAME *result = (tBTA_REMOTE_DEV_NAME *)p_data;

@@ -798,6 +825,7 @@ void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)

798 825

case BTC_GAP_BT_ACT_SET_AFH_CHANNELS:

799 826

case BTC_GAP_BT_ACT_READ_REMOTE_NAME:

800 827

case BTC_GAP_BT_ACT_SET_QOS:

828 +

case BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES:

801 829

break;

802 830

#if (BT_SSP_INCLUDED == TRUE)

803 831

case BTC_GAP_BT_ACT_PASSKEY_REPLY:

@@ -864,6 +892,7 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg)

864 892

case BTC_GAP_BT_ACT_SET_AFH_CHANNELS:

865 893

case BTC_GAP_BT_ACT_READ_REMOTE_NAME:

866 894

case BTC_GAP_BT_ACT_SET_QOS:

895 +

case BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES:

867 896

break;

868 897

#if (BT_SSP_INCLUDED == TRUE)

869 898

case BTC_GAP_BT_ACT_PASSKEY_REPLY:

@@ -966,6 +995,10 @@ void btc_gap_bt_call_handler(btc_msg_t *msg)

966 995

btc_gap_bt_set_qos(arg);

967 996

break;

968 997

}

998 +

case BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES: {

999 +

btc_gap_set_acl_pkt_types(arg);

1000 +

break;

1001 +

}

969 1002

default:

970 1003

break;

971 1004

}

@@ -1009,6 +1042,7 @@ void btc_gap_bt_cb_deep_free(btc_msg_t *msg)

1009 1042

case BTC_GAP_BT_REMOVE_BOND_DEV_COMPLETE_EVT:

1010 1043

case BTC_GAP_BT_QOS_EVT:

1011 1044

#if (BT_SSP_INCLUDED == TRUE)

1045 +

case BTC_GAP_BT_SET_ACL_PKT_TYPES_EVT:

1012 1046

case BTC_GAP_BT_CFM_REQ_EVT:

1013 1047

case BTC_GAP_BT_KEY_NOTIF_EVT:

1014 1048

case BTC_GAP_BT_KEY_REQ_EVT:

@@ -1093,6 +1127,10 @@ void btc_gap_bt_cb_handler(btc_msg_t *msg)

1093 1127

btc_gap_bt_cb_to_app(ESP_BT_GAP_QOS_CMPL_EVT, (esp_bt_gap_cb_param_t *)msg->arg);

1094 1128

break;

1095 1129

}

1130 +

case BTC_GAP_BT_SET_ACL_PKT_TYPES_EVT: {

1131 +

btc_gap_bt_cb_to_app(ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT, (esp_bt_gap_cb_param_t *)msg->arg);

1132 +

break;

1133 +

}

1096 1134

default:

1097 1135

BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act);

1098 1136

break;

Original file line number Diff line number Diff line change

@@ -1,5 +1,5 @@

1 1

/*

2 -

* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD

2 +

* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD

3 3

*

4 4

* SPDX-License-Identifier: Apache-2.0

5 5

*/

@@ -31,6 +31,7 @@ typedef enum {

31 31

BTC_GAP_BT_MODE_CHG_EVT,

32 32

BTC_GAP_BT_REMOVE_BOND_DEV_COMPLETE_EVT,

33 33

BTC_GAP_BT_QOS_EVT,

34 +

BTC_GAP_BT_SET_ACL_PKT_TYPES_EVT,

34 35

}btc_gap_bt_evt_t;

35 36 36 37

typedef enum {

@@ -51,6 +52,7 @@ typedef enum {

51 52

BTC_GAP_BT_ACT_SET_AFH_CHANNELS,

52 53

BTC_GAP_BT_ACT_READ_REMOTE_NAME,

53 54

BTC_GAP_BT_ACT_SET_QOS,

55 +

BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES,

54 56

} btc_gap_bt_act_t;

55 57 56 58

/* btc_bt_gap_args_t */

@@ -147,6 +149,12 @@ typedef union {

147 149

uint32_t t_poll;

148 150

} set_qos;

149 151 152 +

// BTC_GAP_BT_ACT_SET_ACL_PKT_TYPES

153 +

struct set_acl_pkt_types_args {

154 +

bt_bdaddr_t bda;

155 +

uint16_t pkt_types;

156 +

} set_acl_pkt_types;

157 + 150 158

} btc_gap_bt_args_t;

151 159 152 160

void btc_gap_bt_call_handler(btc_msg_t *msg);

You can’t perform that action at this time.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4