BLE4.0核心规格(九)BLE LL的应答问题

在LL连接状态中,LL的acknowledgement 和flow control是一直存在的。每次连接时,transmitSeqNum 和nextExpectedSeqNum都必须设置成0。transmitSeqNum 和nextExpectedSeqNum都只有1bit。transmitSeqNum 用来识别数据包是否被传出去。nextExpectedSeqNum 用来区别是否是最新的数据或者被用来请求重传。当重传一个数据通道的的PDU时,这个PDU的LLID,SN,和payload也要与上一个保持一致。


连接时,transmitSeqNum和nextExpectedSeqNum都被初始化为0;

1.发送方:当transmitSeqNum等于接收到的NESH时,说明发送方没收到确认,这时应该重发。此时SN,NESN,payload,LLID应该保持与上一个一致。当transmitSeqNum不等于接收到的NESH时,发送新的数据包,transmitSeqNum加一,并更新到SN。
接收方:当接收到的SN不等于nextExpectedSeqNum时,接收方忽略或者作为重传数据处理。当接收到的SN与本身的nextExpectedSeqNum一致时,认为这是一个新的数据包。

 这个图的表述其实是有问题的。实际上只有在接收数据时才会对transmitSeqNum和nextExpectedSeqNum进行加一操作的。
 

static int isr_rx_pdu(struct lll_conn *lll, struct pdu_data *pdu_data_rx,
		      struct node_tx **tx_release, u8_t *is_rx_enqueue)
{
	/* Ack for tx-ed data */
	if (pdu_data_rx->nesn != lll->sn) {
		/* Increment serial number */
		lll->sn++;

		/* First ack (and redundantly any other ack) enable use of
		 * slave latency.
		 */
		if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && lll->role) {
			lll->slave.latency_enabled = 1;
		}

		if (!lll->empty) {
			struct pdu_data *pdu_data_tx;
			u8_t pdu_data_tx_len;
			struct node_tx *tx;
			memq_link_t *link;

			link = memq_peek(lll->memq_tx.head, lll->memq_tx.tail,
					 (void **)&tx);
			LL_ASSERT(link);

			pdu_data_tx = (void *)(tx->pdu +
					       lll->packet_tx_head_offset);

			pdu_data_tx_len = pdu_data_tx->len;
#if defined(CONFIG_BT_CTLR_LE_ENC)
			if (pdu_data_tx_len != 0U) {
				/* if encrypted increment tx counter */
				if (lll->enc_tx) {
					lll->ccm_tx.counter++;
				}
			}
#endif /* CONFIG_BT_CTLR_LE_ENC */

			lll->packet_tx_head_offset += pdu_data_tx_len;
			if (lll->packet_tx_head_offset ==
			    lll->packet_tx_head_len) {
				lll->packet_tx_head_len = 0;
				lll->packet_tx_head_offset = 0;

				memq_dequeue(lll->memq_tx.tail,
					     &lll->memq_tx.head, NULL);

				link->next = tx->next;
				tx->next = link;

				*tx_release = tx;
			}
		} else {
			lll->empty = 0;
		}
	}

	/* process received data */
	if ((pdu_data_rx->sn == lll->nesn) &&
	    /* check so that we will NEVER use the rx buffer reserved for empty
	     * packet and internal control enqueue
	     */
	    (ull_pdu_rx_alloc_peek(3) != 0)) {
		/* Increment next expected serial number */
		lll->nesn++;

		if (pdu_data_rx->len != 0) {
#if defined(CONFIG_BT_CTLR_LE_ENC)
			/* If required, wait for CCM to finish
			 */
			if (lll->enc_rx) {
				u32_t done;

				done = radio_ccm_is_done();
				LL_ASSERT(done);

				if (!radio_ccm_mic_is_valid()) {
					/* Record MIC invalid */
					mic_state = LLL_CONN_MIC_FAIL;

					return -EINVAL;
				}

				/* Increment counter */
				lll->ccm_rx.counter++;

				/* Record MIC valid */
				mic_state = LLL_CONN_MIC_PASS;
			}
#endif /* CONFIG_BT_CTLR_LE_ENC */

			/* Enqueue non-empty PDU */
			*is_rx_enqueue = 1U;
		}
	}

	return 0;
}


其核心在以下两端代码

    /* Ack for tx-ed data */

    if (pdu_data_rx->nesn != lll->sn) {

        /* Increment serial number */

        lll->sn++;



    	/* process received data */
	if ((pdu_data_rx->sn == lll->nesn) &&
	    /* check so that we will NEVER use the rx buffer reserved for empty
	     * packet and internal control enqueue
	     */
	    (ull_pdu_rx_alloc_peek(3) != 0)) {
		/* Increment next expected serial number */
		lll->nesn++;

在发送前需要更新SN和NESN的。

    /* Fill sn and nesn */

    pdu_data_tx->sn = lll->sn;

    pdu_data_tx->nesn = lll->nesn;

 

Master传输方向Slave
SNtransmitSeqNumNESNnextExpectedSeqNum SNtransmitSeqNumNESNnextExpectedSeqNum
0000----->0000
0010<-----0011
1111----->1011
1101<------1100
0000----->0000

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值