#define BTM_DEFAULT_DISC_INTERVAL 0x0800
#endif
-/*
+/*
* {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS}
*
* SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object Transfer,Bit22 -Telephony)
#define BTM_BLE_CONFORMANCE_TESTING FALSE
#endif
+/******************************************************************************
+**
+** CONTROLLER TO HOST FLOW CONTROL
+**
+******************************************************************************/
+
+#define C2H_FLOW_CONTROL_INCLUDED TRUE
+
/******************************************************************************
**
** L2CAP
response, &acl_data_size_classic, &acl_buffer_count_classic,
&sco_data_size, &sco_buffer_count);
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+ // Enable controller to host flow control
+ response = AWAIT_COMMAND(packet_factory->make_set_c2h_flow_control(HCI_HOST_FLOW_CTRL_ACL_ON));
+ packet_parser->parse_generic_command_complete(response);
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
+
// Tell the controller about our buffer sizes and buffer counts next
// TODO(zachoverflow): factor this out. eww l2cap contamination. And why just a hardcoded 10?
response = AWAIT_COMMAND(
#include "osi/thread.h"
#include "esp_bt.h"
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+#include "l2c_int.h"
+#include "stack/hcimsgs.h"
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
+
#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
#define HCI_BLE_EVENT 0x3e
#define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2)
if (pdTRUE == xQueueReceive(xHciH4Queue, &e, (portTickType)portMAX_DELAY)) {
if (e.sig == SIG_HCI_HAL_RECV_PACKET) {
fixed_queue_process(hci_hal_env.rx_q);
+
}
}
}
return TASK_POST_FAIL;
}
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+static void hci_packet_complete(BT_HDR *packet){
+ uint8_t type, num_handle;
+ uint16_t handle;
+ uint16_t handles[MAX_L2CAP_LINKS + 4];
+ uint16_t num_packets[MAX_L2CAP_LINKS + 4];
+ uint8_t *stream = packet->data + packet->offset;
+ tL2C_LCB *p_lcb = NULL;
+
+ STREAM_TO_UINT8(type, stream);
+ if (type == DATA_TYPE_ACL/* || type == DATA_TYPE_SCO*/) {
+ STREAM_TO_UINT16(handle, stream);
+ handle = handle & HCI_DATA_HANDLE_MASK;
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+ if (p_lcb) {
+ p_lcb->completed_packets++;
+ }
+ if (esp_vhci_host_check_send_available()){
+ num_handle = l2cu_find_completed_packets(handles, num_packets);
+ if (num_handle > 0){
+ btsnd_hcic_host_num_xmitted_pkts (num_handle, handles, num_packets);
+ }
+ } else {
+ //Send HCI_Host_Number_of_Completed_Packets next time.
+ }
+
+ }
+}
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
+
+
static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet)
{
uint8_t type, hdr_size;
if (!packet) {
return;
}
+
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+ hci_packet_complete(packet);
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
+
STREAM_TO_UINT8(type, stream);
packet->offset++;
packet->len--;
fixed_queue_enqueue(hci_host_env.command_queue, wait_entry);
hci_host_task_post(TASK_POST_BLOCKING);
+
}
static future_t *transmit_command_futured(BT_HDR *command)
command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q;
wait_entry = fixed_queue_dequeue(queue);
- hci_host_env.command_credits--;
+ if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE){
+ packet_fragmenter->fragment_and_dispatch(wait_entry->command);
+ buffer_allocator->free(wait_entry->command);
+ osi_free(wait_entry);
+ return;
+ }
+ hci_host_env.command_credits--;
// Move it to the list of commands awaiting response
osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
list_append(cmd_wait_q->commands_pending_response, wait_entry);
if (event_code == HCI_COMMAND_COMPLETE_EVT) {
STREAM_TO_UINT8(hci_host_env.command_credits, stream);
STREAM_TO_UINT16(opcode, stream);
-
wait_entry = get_waiting_command(opcode);
if (!wait_entry) {
HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
return make_command_no_params(HCI_READ_BUFFER_SIZE);
}
+static BT_HDR *make_set_c2h_flow_control(uint8_t enable)
+{
+ uint8_t *stream;
+ const uint8_t parameter_size = 1;
+ BT_HDR *packet = make_command(HCI_SET_HC_TO_HOST_FLOW_CTRL, parameter_size, &stream);
+
+ UINT8_TO_STREAM(stream, enable);
+ return packet;
+}
+
static BT_HDR *make_host_buffer_size(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count)
{
uint8_t *stream;
static const hci_packet_factory_t interface = {
make_reset,
make_read_buffer_size,
+ make_set_c2h_flow_control,
make_host_buffer_size,
make_read_local_version_info,
make_read_bd_addr,
typedef struct {
BT_HDR *(*make_reset)(void);
BT_HDR *(*make_read_buffer_size)(void);
+ BT_HDR *(*make_set_c2h_flow_control)(uint8_t enable);
BT_HDR *(*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size, uint16_t acl_count, uint16_t sco_count);
BT_HDR *(*make_read_local_version_info)(void);
BT_HDR *(*make_read_bd_addr)(void);
#define HCI_ERR_MAX_ERR 0x43
//ESP vendor error code
-#define HCI_ERR_ESP_VENDOR_FAIL 0xE0
+#define HCI_ERR_ESP_VENDOR_FAIL 0xE0
#define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK 0xFF
TIMER_LIST_ENT timer_entry; /* Timer list entry for timeout evt */
UINT16 handle; /* The handle used with LM */
+ UINT16 completed_packets; /* The number of conpleted packets */
tL2C_CCB_Q ccb_queue; /* Queue of CCBs on this LCB */
#endif
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+extern UINT8 l2cu_find_completed_packets(UINT16 *handles, UINT16 *num_packets);
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
+
extern BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
extern void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
extern void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
btu_free_timer(&p_lcb->timer_entry);
btu_free_timer(&p_lcb->info_timer_entry);
btu_free_timer(&p_lcb->upda_con_timer);
-
+
memset (p_lcb, 0, sizeof (tL2C_LCB));
memcpy (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN);
l2c_link_adjust_allocation();
}
p_lcb->link_xmit_data_q = list_new(NULL);
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+ p_lcb->completed_packets = 0;
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
return (p_lcb);
}
}
memset(&p_lcb->info_timer_entry, 0, sizeof(TIMER_LIST_ENT));
btu_free_timer(&p_lcb->upda_con_timer);
memset(&p_lcb->upda_con_timer, 0, sizeof(TIMER_LIST_ENT));
-
+
/* Release any unfinished L2CAP packet on this link */
if (p_lcb->p_hcit_rcv_acl) {
osi_free(p_lcb->p_hcit_rcv_acl);
fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
p_lcb->le_sec_pending_q = NULL;
}
+
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+ p_lcb->completed_packets = 0;
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
+
}
btu_free_quick_timer(&p_ccb->fcrb.ack_timer);
memset(&p_ccb->fcrb.ack_timer, 0, sizeof(TIMER_LIST_ENT));
p_ccb->fcrb.ack_timer.param = (TIMER_PARAM_TYPE)p_ccb;
-
+
btu_free_quick_timer(&p_ccb->fcrb.mon_retrans_timer);
memset(&p_ccb->fcrb.mon_retrans_timer, 0, sizeof(TIMER_LIST_ENT));
p_ccb->fcrb.mon_retrans_timer.param = (TIMER_PARAM_TYPE)p_ccb;
#endif /* BLE_INCLUDED == TRUE */
+#if (C2H_FLOW_CONTROL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function l2cu_find_completed_packets
+**
+** Description Find the completed packets,
+** Then set it to zero
+**
+** Returns The num of handles
+**
+*******************************************************************************/
+UINT8 l2cu_find_completed_packets(UINT16 *handles, UINT16 *num_packets)
+{
+ int xx;
+ UINT8 num = 0;
+ tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->completed_packets > 0)) {
+ *(handles++) = p_lcb->handle;
+ *(num_packets++) = p_lcb->completed_packets;
+ num++;
+ p_lcb->completed_packets = 0;
+ }
+ }
+
+ return num;
+}
+#endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE
/*******************************************************************************
** Functions used by both Full and Light Stack
-Subproject commit a3070a4a8c4dddc4dcb13576e468f424d78c598e
+Subproject commit 2e3296c0ad97117bf9ce97e5f1330ec0077bfe4f
typedef struct {
int duration_ms; /* parent weak RSSI monitor duration, if the RSSI continues to be weak during this duration_ms,
will switch to a better parent */
- int cnx_rssi; /* RSSI threshold for keeping a good connection with parent */
+ int cnx_rssi; /* RSSI threshold for keeping a good connection with parent.
+ if set a value greater than -120 dBm, will arm a timer to monitor current RSSI at a period time of
+ duration_ms. if keep the default value(-120 dBm), a timer at a random period(<3minutes) will
+ be armed to switch a better parent if there does have one.
+ The better parent must have RSSI greater than a high RSSI threshold(-78 dBm by default) and a top layer
+ than current one. */
int select_rssi; /* RSSI threshold for parent selection, should be a value greater than switch_rssi */
- int switch_rssi; /* RSSI threshold for action to reselect a better parent */
+ int switch_rssi; /* Disassociate current parent and switch to a new parent when the RSSI is greater than this set threshold */
int backoff_rssi; /* RSSI threshold for connecting to the root */
} mesh_switch_parent_t;
+typedef struct {
+ int high;
+ int medium;
+ int low;
+} mesh_rssi_threshold_t;
+
/**
* @brief mesh networking IE
*/
uint16_t self_cap; /**< self capacity */
uint16_t layer2_cap; /**< layer2 capacity */
uint16_t scan_ap_num; /**< the number of scanned APs */
- int8_t rssi; /**< rssi of the parent */
- int8_t router_rssi; /**< rssi of the router */
+ int8_t rssi; /**< RSSI of the parent */
+ int8_t router_rssi; /**< RSSI of the router */
uint8_t flag; /**< flag of networking */
uint8_t rc_addr[6]; /**< root address */
- int8_t rc_rssi; /**< root rssi */
+ int8_t rc_rssi; /**< root RSSI */
uint8_t vote_addr[6]; /**< voter address */
- int8_t vote_rssi; /**< vote rssi of the router */
+ int8_t vote_rssi; /**< vote RSSI of the router */
uint8_t vote_ttl; /**< vote ttl */
uint16_t votes; /**< votes */
uint16_t my_votes; /**< my votes */
*
* @return
* - ESP_OK
- * - ESP_FAIL
+ * - ESP_ERR_MESH_ARGUMENT
*/
esp_err_t esp_mesh_get_attempts(mesh_attempts_t *attempts);
*
* @return
* - ESP_OK
- * - ESP_FAIL
+ * - ESP_ERR_MESH_ARGUMENT
*/
esp_err_t esp_mesh_set_switch_parent_paras(mesh_switch_parent_t *paras);
*
* @return
* - ESP_OK
- * - ESP_FAIL
+ * - ESP_ERR_MESH_ARGUMENT
*/
esp_err_t esp_mesh_get_switch_parent_paras(mesh_switch_parent_t *paras);
+/**
+ * @brief set RSSI threshold
+ * The default high RSSI threshold value is -78 dBm.
+ * The default medium RSSI threshold value is -82 dBm.
+ * The default low RSSI threshold value is -85 dBm.
+ *
+ * @param threshold RSSI threshold
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_ERR_MESH_ARGUMENT
+ */
+esp_err_t esp_mesh_set_rssi_threshold(const mesh_rssi_threshold_t *threshold);
+
+/**
+ * @brief get RSSI threshold
+ * @param threshold RSSI threshold
+ *
+ * @return
+ * - ESP_OK
+ * - ESP_ERR_MESH_ARGUMENT
+ */
+esp_err_t esp_mesh_get_rssi_threshold(mesh_rssi_threshold_t *threshold);
+
+/**
+ * @brief enable the minimum rate to 6Mbps
+ *
+ * @attention This API shall be called before WiFi start.
+ *
+ * @param is_6m enable or not
+ *
+ * @return
+ * - ESP_OK
+ */
+esp_err_t esp_mesh_set_6m_rate(bool is_6m);
+
/**
* @brief print the number of txQ waiting
*
*/
int esp_mesh_get_passive_scan_time(void);
+/**
+ * @brief set announce interval
+ * The default short interval is 500 milliseconds.
+ * The default long interval is 3000 milliseconds.
+ *
+ * @param short_ms shall be greater than the default value
+ * @param long_ms shall be greater than the default value
+ *
+ * @return
+ * - ESP_OK
+ */
+esp_err_t esp_mesh_set_announce_interval(int short_ms, int long_ms);
+
+/**
+ * @brief get announce interval
+ *
+ * @param short_ms short interval
+ * @param long_ms long interval
+ *
+ * @return
+ * - ESP_OK
+ */
+esp_err_t esp_mesh_get_announce_interval(int *short_ms, int *long_ms);
#ifdef __cplusplus
}
-Subproject commit 67fe3bdfb2f82b1befed076c659951bc03a54eed
+Subproject commit 1f2b30fc41b17d1fe8cca26e90d5665f212bfaa9
memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD,
strlen(CONFIG_MESH_AP_PASSWD));
ESP_ERROR_CHECK(esp_mesh_set_config(&cfg));
- /* set RSSI threshold for connecting to the root */
- mesh_switch_parent_t switch_paras ;
- ESP_ERROR_CHECK(esp_mesh_get_switch_parent_paras(&switch_paras));
- switch_paras.select_rssi = -55;
- switch_paras.cnx_rssi = -65;
- switch_paras.duration_ms = 120 * 1000;
- switch_paras.switch_rssi = -65;
- ESP_ERROR_CHECK(esp_mesh_set_switch_parent_paras(&switch_paras));
/* mesh start */
ESP_ERROR_CHECK(esp_mesh_start());
ESP_LOGI(MESH_TAG, "mesh starts successfully, heap:%d, %s\n", esp_get_free_heap_size(),
--- /dev/null
+# Mesh Manual Networking Example
+
+ESP-MESH provides the function of self-organized networking, but if users disable this function on one node, users must designate a parent for this node.
+
+
+This example demonstrates how to scan a list of parent candidates, choose an appropriate parent and set as the parent of this node.
+
+If no parent is found through this scan, enable the self-organized function to let the ESP-MESH handle it by itself.
+
+Run `make menuconfig` to configure the mesh network channel, router SSID, router password and mesh softAP settings.
+
+When the mesh network is established and if you happen to run this example on ESP-WROVER-KIT boards, the RGB light indicator will show you on which layer devices are. The pink reprents root; the yellow reprents layer 2; the red reprents layer 3; the blue reprents layer 4; the green reprents layer 5; the white reprents layer greater than 5.
+
+