|
31 | 31 |
|
32 | 32 | static struct ble_ll_cs_supp_cap g_ble_ll_cs_local_cap;
|
33 | 33 | static struct ble_ll_cs_sm g_ble_ll_cs_sm[MYNEWT_VAL(BLE_MAX_CONNECTIONS)];
|
| 34 | +static const uint8_t t_ip1[] = {10, 20, 30, 40, 50, 60, 80, 145}; |
| 35 | +static const uint8_t t_ip2[] = {10, 20, 30, 40, 50, 60, 80, 145}; |
| 36 | +static const uint8_t t_fcs[] = {15, 20, 30, 40, 50, 60, 80, 100, 120, 150}; |
| 37 | +static const uint8_t t_pm[] = {10, 20, 40}; |
34 | 38 |
|
35 | 39 | int
|
36 | 40 | ble_ll_cs_hci_rd_loc_supp_cap(uint8_t *rspbuf, uint8_t *rsplen)
|
@@ -432,16 +436,300 @@ ble_ll_cs_hci_wr_cached_rem_fae(const uint8_t *cmdbuf, uint8_t cmdlen,
|
432 | 436 | return BLE_ERR_SUCCESS;
|
433 | 437 | }
|
434 | 438 |
|
| 439 | +void |
| 440 | +ble_ll_cs_config_req_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr) |
| 441 | +{ |
| 442 | + uint8_t config_id = connsm->cssm->config_req_id; |
| 443 | + uint8_t action = connsm->cssm->config_req_action; |
| 444 | + const struct ble_ll_cs_config *conf = &connsm->cssm->config[config_id]; |
| 445 | + |
| 446 | + *dptr = config_id | action << 6; |
| 447 | + |
| 448 | + if (action == 0x00) { |
| 449 | + /* Removing the config, all remaining fields are RFU. */ |
| 450 | + memset(dptr + 1, 0, 26); |
| 451 | + |
| 452 | + return; |
| 453 | + } |
| 454 | + |
| 455 | + memcpy(dptr + 1, conf->chan_map, 10); |
| 456 | + dptr[11] = conf->chan_map_repetition; |
| 457 | + dptr[12] = conf->main_mode; |
| 458 | + dptr[13] = conf->sub_mode; |
| 459 | + dptr[14] = conf->main_mode_min_steps; |
| 460 | + dptr[15] = conf->main_mode_max_steps; |
| 461 | + dptr[16] = conf->main_mode_repetition; |
| 462 | + dptr[17] = conf->mode_0_steps; |
| 463 | + dptr[18] = conf->cs_sync_phy; |
| 464 | + dptr[19] = conf->rtt_type | |
| 465 | + conf->role << 4; |
| 466 | + dptr[20] = conf->chan_sel | |
| 467 | + conf->ch3cshape << 4; |
| 468 | + dptr[21] = conf->ch3cjump; |
| 469 | + dptr[22] = conf->t_ip1; |
| 470 | + dptr[23] = conf->t_ip2; |
| 471 | + dptr[24] = conf->t_fcs; |
| 472 | + dptr[25] = conf->t_pm; |
| 473 | + /* RFU octet */ |
| 474 | + dptr[26] = 0x00; |
| 475 | +} |
| 476 | + |
| 477 | +int |
| 478 | +ble_ll_cs_rx_config_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, |
| 479 | + uint8_t *rspbuf) |
| 480 | +{ |
| 481 | + struct ble_ll_cs_config *conf; |
| 482 | + uint8_t config_id = *dptr & 0b00111111; |
| 483 | + uint8_t action = (*dptr & 0b11000000) >> 6; |
| 484 | + |
| 485 | + if (config_id >= BLE_LL_CS_CONFIG_MAX_NUM) { |
| 486 | + /* LL_REJECT_EXT_IND */ |
| 487 | + rej_ext_ind_make(BLE_LL_CTRL_CS_CONFIG_REQ, BLE_ERR_INV_LMP_LL_PARM, |
| 488 | + rspbuf); |
| 489 | + |
| 490 | + return BLE_LL_CTRL_REJECT_IND_EXT; |
| 491 | + } |
| 492 | + |
| 493 | + conf = &connsm->cssm->config[config_id]; |
| 494 | + memset(conf, 0, sizeof(*conf)); |
| 495 | + |
| 496 | + /* Respond with LL_CS_CONFIG_RSP PDU */ |
| 497 | + *rspbuf = config_id | action << 6; |
| 498 | + |
| 499 | + if (action == 0x00) { |
| 500 | + /* CS configuration removed. */ |
| 501 | + return BLE_LL_CTRL_CS_CONFIG_RSP; |
| 502 | + } |
| 503 | + |
| 504 | + memcpy(conf->chan_map, dptr + 1, 10); |
| 505 | + conf->chan_map_repetition = dptr[11]; |
| 506 | + conf->main_mode = dptr[12]; |
| 507 | + conf->sub_mode = dptr[13]; |
| 508 | + conf->main_mode_min_steps = dptr[14]; |
| 509 | + conf->main_mode_max_steps = dptr[15]; |
| 510 | + conf->main_mode_repetition = dptr[16]; |
| 511 | + conf->mode_0_steps = dptr[17]; |
| 512 | + conf->cs_sync_phy = dptr[18]; |
| 513 | + conf->rtt_type = dptr[19] & 0b00001111; |
| 514 | + conf->role = (~dptr[19] >> 4) & 0b00000001; |
| 515 | + conf->chan_sel = (dptr[20] & 0b00001111); |
| 516 | + conf->ch3cshape = (dptr[20] & 0b11110000) >> 4; |
| 517 | + conf->ch3cjump = dptr[21]; |
| 518 | + conf->t_ip1 = dptr[22]; |
| 519 | + conf->t_ip2 = dptr[23]; |
| 520 | + conf->t_fcs = dptr[24]; |
| 521 | + conf->t_pm = dptr[25]; |
| 522 | + conf->config_enabled = true; |
| 523 | + |
| 524 | + return BLE_LL_CTRL_CS_CONFIG_RSP; |
| 525 | +} |
| 526 | + |
| 527 | +static void |
| 528 | +ble_ll_cs_ev_config_complete(struct ble_ll_conn_sm *connsm, uint8_t config_id, |
| 529 | + uint8_t action, uint8_t status) |
| 530 | +{ |
| 531 | + struct ble_hci_ev_le_subev_cs_config_complete *ev; |
| 532 | + const struct ble_ll_cs_config *conf; |
| 533 | + struct ble_hci_ev *hci_ev; |
| 534 | + |
| 535 | + if (ble_ll_hci_is_le_event_enabled( |
| 536 | + BLE_HCI_LE_SUBEV_CS_CONFIG_COMPLETE)) { |
| 537 | + hci_ev = ble_transport_alloc_evt(0); |
| 538 | + if (hci_ev) { |
| 539 | + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; |
| 540 | + hci_ev->length = sizeof(*ev); |
| 541 | + ev = (void *) hci_ev->data; |
| 542 | + |
| 543 | + memset(ev, 0, sizeof(*ev)); |
| 544 | + ev->subev_code = BLE_HCI_LE_SUBEV_CS_CONFIG_COMPLETE; |
| 545 | + ev->status = status; |
| 546 | + ev->conn_handle = htole16(connsm->conn_handle); |
| 547 | + ev->config_id = config_id; |
| 548 | + ev->action = action; |
| 549 | + |
| 550 | + if (action == 0x00) { |
| 551 | + /* CS configuration removed. */ |
| 552 | + return; |
| 553 | + } |
| 554 | + |
| 555 | + conf = &connsm->cssm->config[config_id]; |
| 556 | + ev->main_mode_type = conf->main_mode; |
| 557 | + ev->sub_mode_type = conf->sub_mode; |
| 558 | + ev->min_main_mode_steps = conf->main_mode_min_steps; |
| 559 | + ev->max_main_mode_steps = conf->main_mode_max_steps; |
| 560 | + ev->main_mode_repetition = conf->main_mode_repetition; |
| 561 | + ev->mode_0_steps = conf->mode_0_steps; |
| 562 | + ev->role = conf->role; |
| 563 | + ev->rtt_type = conf->rtt_type; |
| 564 | + ev->cs_sync_phy = conf->cs_sync_phy; |
| 565 | + memcpy(ev->channel_map, conf->chan_map, 10); |
| 566 | + ev->channel_map_repetition = conf->chan_map_repetition; |
| 567 | + ev->channel_selection_type = conf->chan_sel; |
| 568 | + ev->ch3c_shape = conf->ch3cshape; |
| 569 | + ev->ch3c_jump = conf->ch3cjump; |
| 570 | + ev->reserved = 0x00; |
| 571 | + ev->t_ip1_time = conf->t_ip1; |
| 572 | + ev->t_ip2_time = conf->t_ip2; |
| 573 | + ev->t_fcs_time = conf->t_fcs; |
| 574 | + ev->t_pm_time = conf->t_pm; |
| 575 | + |
| 576 | + ble_ll_hci_event_send(hci_ev); |
| 577 | + } |
| 578 | + } |
| 579 | +} |
| 580 | + |
| 581 | +void |
| 582 | +ble_ll_cs_rx_config_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) |
| 583 | +{ |
| 584 | + uint8_t config_id = *dptr & 0b00111111; |
| 585 | + uint8_t action = (*dptr & 0b11000000) >> 6; |
| 586 | + |
| 587 | + if (config_id != connsm->cssm->config_req_id || |
| 588 | + !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CS_CONF)) { |
| 589 | + return; |
| 590 | + } |
| 591 | + |
| 592 | + /* Stop the control procedure and send an event to the host */ |
| 593 | + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CS_CONF); |
| 594 | + ble_ll_cs_ev_config_complete(connsm, config_id, action, BLE_ERR_SUCCESS); |
| 595 | +} |
| 596 | + |
| 597 | +static int |
| 598 | +ble_ll_cs_select_capability(const uint8_t *capability_values, uint8_t len, |
| 599 | + uint8_t *out_value, uint16_t local_capability, |
| 600 | + uint16_t remote_capability) |
| 601 | +{ |
| 602 | + uint16_t common_capability = local_capability & remote_capability; |
| 603 | + uint8_t i; |
| 604 | + |
| 605 | + for (i = 0; i < len; i++) { |
| 606 | + if ((common_capability >> i) & 1) { |
| 607 | + *out_value = capability_values[i]; |
| 608 | + return 0; |
| 609 | + } |
| 610 | + } |
| 611 | + |
| 612 | + return 1; |
| 613 | +} |
| 614 | + |
435 | 615 | int
|
436 | 616 | ble_ll_cs_hci_create_config(const uint8_t *cmdbuf, uint8_t cmdlen)
|
437 | 617 | {
|
438 |
| - return BLE_ERR_UNSUPPORTED; |
| 618 | + const struct ble_hci_le_cs_create_config_cp *cmd = (const void *)cmdbuf; |
| 619 | + struct ble_ll_conn_sm *connsm; |
| 620 | + struct ble_ll_cs_config *conf; |
| 621 | + struct ble_ll_cs_sm *cssm; |
| 622 | + |
| 623 | + if (cmdlen != sizeof(*cmd) || cmd->config_id >= BLE_LL_CS_CONFIG_MAX_NUM) { |
| 624 | + return BLE_ERR_INV_HCI_CMD_PARMS; |
| 625 | + } |
| 626 | + |
| 627 | + /* If no connection handle exit with error */ |
| 628 | + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle)); |
| 629 | + if (!connsm) { |
| 630 | + return BLE_ERR_UNK_CONN_ID; |
| 631 | + } |
| 632 | + |
| 633 | + cssm = connsm->cssm; |
| 634 | + |
| 635 | + /* If already pending exit with error */ |
| 636 | + if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CS_CONF)) { |
| 637 | + return BLE_ERR_CMD_DISALLOWED; |
| 638 | + } |
| 639 | + |
| 640 | + /* Configure CS config locally */ |
| 641 | + conf = &cssm->config[cmd->config_id]; |
| 642 | + conf->config_enabled = true; |
| 643 | + conf->main_mode = cmd->main_mode_type; |
| 644 | + conf->sub_mode = cmd->sub_mode_type; |
| 645 | + conf->main_mode_min_steps = cmd->min_main_mode_steps; |
| 646 | + conf->main_mode_max_steps = cmd->max_main_mode_steps; |
| 647 | + conf->main_mode_repetition = cmd->main_mode_repetition; |
| 648 | + conf->mode_0_steps = cmd->mode_0_steps; |
| 649 | + conf->role = cmd->role; |
| 650 | + conf->rtt_type = cmd->rtt_type; |
| 651 | + conf->cs_sync_phy = cmd->cs_sync_phy; |
| 652 | + memcpy(conf->chan_map, cmd->channel_map, 10); |
| 653 | + conf->chan_map_repetition = cmd->channel_map_repetition; |
| 654 | + conf->chan_sel = cmd->channel_selection_type; |
| 655 | + conf->ch3cshape = cmd->ch3c_shape; |
| 656 | + conf->ch3cjump = cmd->ch3c_jump; |
| 657 | + |
| 658 | + if (ble_ll_cs_select_capability(t_ip1, ARRAY_SIZE(t_ip1), &conf->t_ip1, |
| 659 | + cssm->remote_cap.t_ip1_capability, |
| 660 | + g_ble_ll_cs_local_cap.t_ip1_capability)) { |
| 661 | + memset(conf, 0, sizeof(*conf)); |
| 662 | + return BLE_ERR_INV_HCI_CMD_PARMS; |
| 663 | + } |
| 664 | + |
| 665 | + if (ble_ll_cs_select_capability(t_ip2, ARRAY_SIZE(t_ip2), &conf->t_ip2, |
| 666 | + cssm->remote_cap.t_ip2_capability, |
| 667 | + g_ble_ll_cs_local_cap.t_ip2_capability)) { |
| 668 | + memset(conf, 0, sizeof(*conf)); |
| 669 | + return BLE_ERR_INV_HCI_CMD_PARMS; |
| 670 | + } |
| 671 | + |
| 672 | + if (ble_ll_cs_select_capability(t_fcs, ARRAY_SIZE(t_fcs), &conf->t_fcs, |
| 673 | + cssm->remote_cap.t_fcs_capability, |
| 674 | + g_ble_ll_cs_local_cap.t_fcs_capability)) { |
| 675 | + memset(conf, 0, sizeof(*conf)); |
| 676 | + return BLE_ERR_INV_HCI_CMD_PARMS; |
| 677 | + } |
| 678 | + |
| 679 | + if (ble_ll_cs_select_capability(t_pm, ARRAY_SIZE(t_pm), &conf->t_pm, |
| 680 | + cssm->remote_cap.t_pm_capability, |
| 681 | + g_ble_ll_cs_local_cap.t_pm_capability)) { |
| 682 | + memset(conf, 0, sizeof(*conf)); |
| 683 | + return BLE_ERR_INV_HCI_CMD_PARMS; |
| 684 | + } |
| 685 | + |
| 686 | + if (cmd->create_context == 0x01) { |
| 687 | + /* Configure the CS config in the remote controller */ |
| 688 | + cssm->config_req_id = cmd->config_id; |
| 689 | + cssm->config_req_action = 0x01; |
| 690 | + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CS_CONF, NULL); |
| 691 | + } else { |
| 692 | + ble_ll_cs_ev_config_complete(connsm, cmd->config_id, 0x01, BLE_ERR_SUCCESS); |
| 693 | + } |
| 694 | + |
| 695 | + return BLE_ERR_SUCCESS; |
439 | 696 | }
|
440 | 697 |
|
441 | 698 | int
|
442 | 699 | ble_ll_cs_hci_remove_config(const uint8_t *cmdbuf, uint8_t cmdlen)
|
443 | 700 | {
|
444 |
| - return BLE_ERR_UNSUPPORTED; |
| 701 | + const struct ble_hci_le_cs_remove_config_cp *cmd = (const void *)cmdbuf; |
| 702 | + struct ble_ll_conn_sm *connsm; |
| 703 | + struct ble_ll_cs_sm *cssm; |
| 704 | + struct ble_ll_cs_config *conf; |
| 705 | + |
| 706 | + if (cmdlen != sizeof(*cmd) || cmd->config_id >= BLE_LL_CS_CONFIG_MAX_NUM) { |
| 707 | + return BLE_ERR_INV_HCI_CMD_PARMS; |
| 708 | + } |
| 709 | + |
| 710 | + /* If no connection handle exit with error */ |
| 711 | + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle)); |
| 712 | + if (!connsm) { |
| 713 | + return BLE_ERR_UNK_CONN_ID; |
| 714 | + } |
| 715 | + |
| 716 | + cssm = connsm->cssm; |
| 717 | + |
| 718 | + /* If already pending exit with error */ |
| 719 | + if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CS_CONF)) { |
| 720 | + return BLE_ERR_CMD_DISALLOWED; |
| 721 | + } |
| 722 | + |
| 723 | + /* Remove the CS config locally */ |
| 724 | + conf = &cssm->config[cmd->config_id]; |
| 725 | + memset(conf, 0, sizeof(*conf)); |
| 726 | + |
| 727 | + /* Configure the CS config in the remote controller */ |
| 728 | + cssm->config_req_id = cmd->config_id; |
| 729 | + cssm->config_req_action = 0x00; |
| 730 | + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CS_CONF, NULL); |
| 731 | + |
| 732 | + return BLE_ERR_SUCCESS; |
445 | 733 | }
|
446 | 734 |
|
447 | 735 | int
|
|
0 commit comments