diff options
| author | Bernhard Guillon <Bernhard.Guillon@begu.org> | 2024-12-25 00:34:42 +0100 |
|---|---|---|
| committer | Bernhard Guillon <Bernhard.Guillon@begu.org> | 2024-12-29 19:54:53 +0100 |
| commit | 1762c56956bafd6fc0636516b494dfa935ff8aec (patch) | |
| tree | 5b693c0c70400b71c982401fd9693a48991d3c23 /usr/space_light/src/lld_re.c | |
| parent | 40404fb81dfad3f5c5cf567bb053796a9135165e (diff) | |
| download | wb3s-ble-nebula-galaxy-1762c56956bafd6fc0636516b494dfa935ff8aec.tar.gz wb3s-ble-nebula-galaxy-1762c56956bafd6fc0636516b494dfa935ff8aec.zip | |
space_light: first version
TODO: pwm initialization is currently best guess
could be wrong active low|high
TODO: implement pairing
TODO: implement timer
TODO: use the button for something
TODO: implement a better client
Diffstat (limited to 'usr/space_light/src/lld_re.c')
| -rw-r--r-- | usr/space_light/src/lld_re.c | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/usr/space_light/src/lld_re.c b/usr/space_light/src/lld_re.c new file mode 100644 index 0000000..22b608b --- /dev/null +++ b/usr/space_light/src/lld_re.c @@ -0,0 +1,459 @@ + +#include "RomCallFlash.h" +#include "ble_reg_access.h" +#include "common_hci.h" +#include "common_llcp.h" +#include "common_utils.h" +#include "ea.h" +#include "ecc_p256.h" +#include "em_buf.h" +#include "em_map_ble.h" +#include "lld.h" +#include "lld_evt.h" +#include "lld_pdu.h" +#include "lld_util.h" +#include "llm.h" +#include "llm_util.h" +#include "reg_ble_em_cs.h" +#include "reg_ble_em_rx_buffer.h" +#include "reg_ble_em_rx_desc.h" +#include "reg_ble_em_tx_buffer_cntl.h" +#include "reg_ble_em_tx_buffer_data.h" +#include "reg_ble_em_tx_desc.h" +#include "reg_blecore.h" +#include "rwip.h" +#include "rwip_config.h" + +extern struct kernel_task_desc TASK_DESC_LLD; + +void lld_init(bool reset) { + + if (reset) { + kernel_task_create(TASK_LLD, &TASK_DESC_LLD); + } + + ble_rxwinszdef_setf(LLD_EVT_DEFAULT_RX_WIN_SIZE); + + ble_prefetch_time_setf(LLD_EVT_PREFETCH_TIME_US); + ble_prefetchabort_time_setf(LLD_EVT_ABORT_CNT_DURATION_US); + + ble_radiopwrupdn0_pack(122, 0, 120); + ble_radiopwrupdn1_pack(122, 0, 120); + ble_intcntl_set(BLE_RXINTMSK_BIT | BLE_EVENTINTMSK_BIT | BLE_CRYPTINTMSK_BIT | + BLE_ERRORINTMSK_BIT | BLE_SWINTMSK_BIT | + BLE_EVENTAPFAINTMSK_BIT); + + ble_sn_dsb_setf(0); + ble_nesn_dsb_setf(0); + + ecc_gen_new_secret_key(&llm_le_env.secret_key256[0], 0); + +#define m(idx, pos) ((uint32_t)(common_default_bdaddr.addr[idx])) << (pos * 8) + ble_bdaddrl_setf(m(0, 0) | m(1, 1) | m(2, 2) | m(3, 3)); + ble_bdaddru_pack(0, m(4, 0) | m(5, 1)); + +#undef mac + + ble_advertfilt_en_setf(0); + + ble_advchmap_setf(0x7); + ble_wlpubaddptr_setf(EM_BLE_WPB_OFFSET); + ble_wlprivaddptr_setf(EM_BLE_WPV_OFFSET); + ble_wlnbdev_pack(BLE_WHITELIST_MAX, BLE_WHITELIST_MAX); + + ble_ralptr_setf(EM_BLE_RAL_OFFSET); + ble_nbraldev_setf(BLE_RESOL_ADDR_LIST_MAX); + + ble_syncwordl_setf(LLD_ADV_HDL, (uint16_t)(0x0000FFFF & LLM_LE_ADV_AA)); + ble_syncwordh_setf(LLD_ADV_HDL, (uint16_t)(LLM_LE_ADV_AA >> 16)); + ble_crcinit0_setf(LLD_ADV_HDL, 0x5555); + ble_crcinit1_setf(LLD_ADV_HDL, 0x55); + ble_llchmap0_setf(LLD_ADV_HDL, 0); + ble_llchmap1_setf(LLD_ADV_HDL, 0); + ble_chmap2_pack(LLD_ADV_HDL, 0, 0); + ble_rxmaxbuf_setf(LLD_ADV_HDL, 0); + ble_rxmaxtime_setf(LLD_ADV_HDL, 0); + ble_et_currentrxdescptr_pack(0, EM_BLE_RX_DESC_OFFSET); + ble_txrxcntl_pack(LLD_ADV_HDL, 0, 0, 0, 0, LLM_ADV_CHANNEL_TXPWR); + + if (system_mode == 1) { + ble_thrcntl_ratecntl_pack(LLD_ADV_HDL, 1, 0, 0); + } else { + ble_thrcntl_ratecntl_pack(LLD_ADV_HDL, 4, 0, 0); + } + + ble_conflict_setf(LLD_ADV_HDL, 0); + ble_filtpol_ralcntl_pack(LLD_ADV_HDL, 0, 0, 0, 0); + em_set(0, 0, 0x40); + + lld_evt_init(reset); + + extern bool system_sleep_flag; + + if (system_sleep_flag) { + lld_sleep_init(); + } + + ble_txpldsrc_setf(0); + + ble_rwble_en_setf(1); +} + +struct ea_elt_tag *lld_adv_start(struct advertising_pdu_params *adv_par, + struct em_desc_node *adv_pdu, + struct em_desc_node *scan_rsp_pdu, + uint8_t adv_pwr) { + + uint32_t adv_time; + uint8_t position; + uint8_t priv_info; + uint32_t ral_pos; + struct ea_elt_tag *elt = NULL; + struct lld_evt_tag *env; + + if (adv_par->type == ADV_CONN_DIR && !adv_par->adv_ldc_flag) { + adv_par->intervalmax = LLM_LE_ADV_INTERV_DFLT; + adv_time = LLD_EVT_FRAME_DURATION; + elt = lld_evt_adv_create(LLD_ADV_HDL, adv_par->intervalmin, + adv_par->intervalmax, false); + } else { + adv_time = LLD_EVT_FRAME_DURATION + DRIFT_BT_DFT; + + elt = lld_evt_adv_create(LLD_ADV_HDL, adv_par->intervalmin, + adv_par->intervalmax, true); + } + + if (!elt) { + return NULL; + } + + env = LLD_EVT_ENV_ADDR_GET(elt); + + priv_info = llm_le_env.enh_priv_info & LLM_PRIV_ENABLE_MASK; + ral_pos = 0; + + if (priv_info) { + ral_pos = 0; + if (adv_par->own_addr_type & ADDR_RPA_MASK) { + if (llm_util_bd_addr_in_ral(&(adv_par->peer_addr), + adv_par->peer_addr_type, &position)) { + ral_pos = EM_BLE_RAL_OFFSET + position * REG_BLE_EM_RAL_SIZE; + } + + priv_info = true; + + if (adv_par->type == ADV_CONN_DIR) { + priv_info = !!ral_pos; + } + } + } + + ble_linklbl_setf(LLD_ADV_HDL, 8); + + if (adv_par->type == ADV_CONN_DIR) { + ble_cntl_pack(LLD_ADV_HDL, 0xff, 0x1, 0, 0, + adv_par->adv_ldc_flag ? LLD_LD_ADVERTISER + : LLD_HD_ADVERTISER); + } else { + ble_cntl_pack(LLD_ADV_HDL, 0xff, 0x1, 0, 0, LLD_LD_ADVERTISER); + } + + uint8_t localrpasel = 0; + + if (adv_par->own_addr_type > ADDR_RAND) { + localrpasel = !!ral_pos; + } + + ble_filtpol_ralcntl_pack(LLD_ADV_HDL, adv_par->filterpolicy, localrpasel, + !!ral_pos, priv_info); + + ble_conflict_setf(LLD_ADV_HDL, 0); + + if (ral_pos) { + ble_peer_ralptr_set(LLD_ADV_HDL, ral_pos); + } else { + em_wr((adv_par->peer_addr).addr, + 2 * BLE_ADV_BD_ADDR_INDEX + EM_BLE_CS_OFFSET + + LLD_ADV_HDL * REG_BLE_EM_CS_SIZE, + BD_ADDR_LEN); + ble_adv_bd_addr_type_set(LLD_ADV_HDL, adv_par->peer_addr_type); + } + + ble_hopcntl_pack(LLD_ADV_HDL, 1, 0x0, 0x27); + ble_crcinit1_set(LLD_ADV_HDL, 0x55); + ble_rxwincntl_set(LLD_ADV_HDL, 0); + ble_txrxcntl_set(LLD_ADV_HDL, adv_pwr); + ble_thrcntl_ratecntl_pack(LLD_ADV_HDL, 0x4, 0, 0); + ble_fcntoffset_set(LLD_ADV_HDL, 0x00); + ble_rxmaxbuf_set(LLD_ADV_HDL, 0x00); + ble_rxmaxtime_set(LLD_ADV_HDL, 0x00); + ble_maxevtime_set(LLD_ADV_HDL, 0x08); + ble_advchmap_set(adv_par->channelmap); + ble_advtim_set(adv_time); + + env->tx_pwr = adv_pwr; + lld_pdu_tx_push(elt, adv_pdu); + + if (scan_rsp_pdu) { + lld_pdu_tx_push(elt, scan_rsp_pdu); + } + + lld_pdu_tx_loop(env); + + void lld_abort_scan_evt(void); + + GLOBAL_INT_DIS(); + + lld_evt_elt_insert(elt, 1); + lld_abort_scan_evt(); + (env->evt).non_conn.anchor = elt->timestamp; + (env->evt).non_conn.end_ts = + CLK_ADD_2(elt->timestamp, LLM_LE_ADV_INTERV_DFLT); + (env->evt).non_conn.initiate = 0; + (env->evt).non_conn.connect_req_sent = 0; + + GLOBAL_INT_RES(); + + return elt; +} + +struct ea_elt_tag *lld_con_start(struct hci_le_create_con_cmd const *con_par, + struct em_desc_node *con_req_pdu, + uint16_t conhdl) { + + struct ea_elt_tag *element1, *element2; + struct lld_evt_tag *environ1, *environ2; + + uint32_t rand_val; + struct ea_param_input in_param; + struct ea_param_output out_param = {0}; + + struct llm_pdu_con_req_tx connreq_pdu; + uint8_t hop_increment = 0; + uint8_t pdu_len = 0; + + uint8_t ral_idx = 0; + uint16_t ral_ptr = 0; + bool ral_en = false; + + element1 = ea_elt_create(sizeof(struct lld_evt_tag)); + + if (!element1) { + return NULL; + } + + element2 = ea_elt_create(sizeof(struct lld_evt_tag)); + + if (!element2) { + kernel_free(element1); + return NULL; + } + + environ1 = LLD_EVT_ENV_ADDR_GET(element1); + environ2 = LLD_EVT_ENV_ADDR_GET(element2); + + element1->start_latency = 2; + element1->duration_min = LLD_EVT_FRAME_DURATION; + element1->stop_latency1 = 0; + element1->stop_latency2 = 0; + + environ1->conhdl = LLD_ADV_HDL; + environ1->mode = LLD_EVT_SCAN_MODE; + environ1->interval = con_par->scan_intv; + environ1->cs_ptr = EM_BLE_CS_OFFSET + LLD_ADV_HDL * REG_BLE_EM_CS_SIZE; + + element2->start_latency = 2; + element2->stop_latency1 = 0; + element2->stop_latency2 = 0; + + (environ1->evt).non_conn.window = SLOT_SIZE * con_par->scan_window; + + lld_evt_init_evt(environ1); + lld_util_priority_set(element1, RWIP_PRIO_INIT_IDX); + + element1->ea_cb_start = lld_evt_schedule; + element1->ea_cb_cancel = lld_evt_canceled; + element1->ea_cb_stop = lld_evt_prevent_stop; + element1->asap_settings = (EA_FLAG_ASAP_NO_LIMIT | EA_NO_PARITY) << 12; + + element1->timestamp = + CLK_ADD_3(element1->start_latency, 3, ea_time_get_halfslot_rounded()) & + SYNC_TRAIN_TO_MAX; + + in_param.interval_min = con_par->con_intv_min * 2; + in_param.interval_max = con_par->con_intv_max * 2; + in_param.duration_min = con_par->ce_len_min; + in_param.duration_max = con_par->ce_len_max; + in_param.pref_period = 0; + in_param.action = 0; + in_param.conhdl = conhdl; + in_param.role = MASTER_ROLE; + in_param.linkid = conhdl * REG_BLE_EM_CS_SIZE + EM_BLE_CS_OFFSET; + + ea_interval_duration_req(&in_param, &out_param); + + in_param.offset = 0; + in_param.odd_offset = 0; + + if (ea_offset_req(&in_param, &out_param) == 1) { + kernel_free(element1); + kernel_free(element2); + + return NULL; + } + + ble_txphadv_pack(con_req_pdu->idx, LLCP_CON_REQ_LEN, + con_par->peer_addr_type & ADDR_MASK, ADDR_PUBLIC, + LL_CONNECT_REQ); + + llm_util_aa_gen(connreq_pdu.aa.addr); + llm_util_get_channel_map(&connreq_pdu.chm); + + rand_val = rand(); + + connreq_pdu.crcinit.crc[2] = (uint8_t)((rand_val & 0x00FF0000) >> 16); + connreq_pdu.crcinit.crc[1] = (uint8_t)((rand_val & 0x0000FF00) >> 8); + connreq_pdu.crcinit.crc[0] = (uint8_t)(rand_val & 0x000000FF); + + connreq_pdu.timeout = con_par->superv_to; + connreq_pdu.latency = con_par->con_latency; + connreq_pdu.winsize = 2; + connreq_pdu.interval = out_param.interval * 2; + + hop_increment = (uint8_t)(rand_val & 0x0000000F); + + if (hop_increment < 5) { + + hop_increment += 5; + } + + connreq_pdu.hop_sca = ((lld_evt_env.sca) << 5) | hop_increment; + + lld_pdu_adv_pack(LL_CONNECT_REQ, (uint8_t *)(&connreq_pdu), &pdu_len); + em_wr(&connreq_pdu, ble_txdataptr_get(LLD_ADV_HDL), pdu_len); + llm_util_apply_bd_addr(con_par->own_addr_type); + + if (!(con_par->peer_addr_type & ADDR_RPA_MASK) && + con_par->own_addr_type & ADDR_RPA_MASK) { + ral_en = true; + if (!(con_par->init_filt_policy) && + llm_util_bd_addr_in_ral(&(con_par->peer_addr), con_par->peer_addr_type, + &ral_idx)) { + ral_ptr = EM_BLE_RAL_OFFSET + ral_idx * REG_BLE_EM_RAL_SIZE; + } + } + + if ((con_par->peer_addr_type & ADDR_RPA_MASK) && + !(con_par->init_filt_policy)) { + ral_en = true; + if (llm_util_bd_addr_in_ral(&(con_par->peer_addr), con_par->peer_addr_type, + &ral_idx)) { + ral_ptr = EM_BLE_RAL_OFFSET + ral_idx * REG_BLE_EM_RAL_SIZE; + } + } + + if ((con_par->peer_addr_type & ADDR_RPA_MASK) && con_par->init_filt_policy) { + ral_en = !!(con_par->own_addr_type & ADDR_RPA_MASK); + } + + element1->linked_element = element2; + lld_pdu_tx_push(element1, con_req_pdu); + lld_util_connection_param_set(element1, &out_param); + + ble_linklbl_setf(LLD_ADV_HDL, 8); + ble_cntl_pack(LLD_ADV_HDL, 0xF, 1, 1, 0, LLD_INITIATING); + + ble_filtpol_ralcntl_pack(LLD_ADV_HDL, con_par->init_filt_policy, + !!(con_par->own_addr_type & ADDR_RPA_MASK), + !!(ral_ptr), ral_en); + + ble_conflict_setf(LLD_ADV_HDL, 0); + ble_hopcntl_pack(LLD_ADV_HDL, 1, 0x0, 0x27); + ble_fcntoffset_set(LLD_ADV_HDL, 0); + + if (ral_ptr) { + ble_peer_ralptr_set(LLD_ADV_HDL, ral_ptr); + } else { + ble_adv_bd_addr_set(LLD_ADV_HDL, 0, + (con_par->peer_addr).addr[0] | + (con_par->peer_addr).addr[1] << 8); + ble_adv_bd_addr_set(LLD_ADV_HDL, 1, + (con_par->peer_addr).addr[2] | + (con_par->peer_addr).addr[3] << 8); + ble_adv_bd_addr_set(LLD_ADV_HDL, 2, + (con_par->peer_addr).addr[4] | + (con_par->peer_addr).addr[5] << 8); + ble_adv_bd_addr_type_setf(LLD_ADV_HDL, con_par->peer_addr_type & ADDR_MASK); + } + + ble_crcinit0_set(LLD_ADV_HDL, 0x5555); + + ble_crcinit1_set(LLD_ADV_HDL, 0x55); + + if (out_param.offset <= 4) { + out_param.offset = connreq_pdu.interval * 2 + out_param.offset; + } + + ble_winoffset_set(conhdl, (out_param.offset / 2 - 1)); + ble_conninterval_set(LLD_ADV_HDL, out_param.interval / 2); + + lld_evt_init_evt(environ2); + + environ2->conhdl = conhdl; + environ2->interval = connreq_pdu.interval * 2; + (environ2->evt).conn.latency = con_par->con_latency + 1; + environ2->mode = LLD_EVT_MST_MODE; + environ2->cs_ptr = conhdl * REG_BLE_EM_CS_SIZE + EM_BLE_CS_OFFSET; + + element2->timestamp = CLK_ADD_2( + CLK_SUB(out_param.offset % environ2->interval, environ2->interval), + element1->timestamp); + + if (con_par->ce_len_min) { + element2->duration_min = SLOT_SIZE * con_par->ce_len_min; + } else { + element2->duration_min = LLD_EVT_FRAME_DURATION; + } + + element2->current_prio = rwip_priority[RWIP_PRIO_LE_CON_IDLE_IDX].value; + element2->ea_cb_start = lld_evt_schedule; + element2->ea_cb_cancel = lld_evt_canceled; + element2->ea_cb_stop = lld_evt_prevent_stop; + + ble_cntl_pack(conhdl, 0, 0, 0, 0, LLD_MASTER_CONNECTED); + ble_fcntoffset_set(conhdl, 0); + ble_txcrypt_en_setf(conhdl, 0); + ble_rxcrypt_en_setf(conhdl, 0); + ble_thrcntl_ratecntl_pack(conhdl, LLD_RX_IRQ_THRES, 0, 0); + ble_syncwordl_setf(conhdl, + connreq_pdu.aa.addr[0] | connreq_pdu.aa.addr[1] << 8); + ble_syncwordh_setf(conhdl, + connreq_pdu.aa.addr[2] | connreq_pdu.aa.addr[3] << 8); + ble_crcinit0_set(conhdl, connreq_pdu.crcinit.crc[0] | + connreq_pdu.crcinit.crc[1] << 8); + ble_crcinit1_set(conhdl, connreq_pdu.crcinit.crc[2]); + ble_hopcntl_pack(conhdl, 1, hop_increment, 0); + ble_txrxcntl_pack(conhdl, 0, 0, 0, 0, rwip_rf.txpwr_max); + ble_maxevtime_set(conhdl, environ2->interval - element2->start_latency); + ble_linklbl_setf(conhdl, conhdl); + ble_rxmaxbuf_set(conhdl, 0); + ble_rxmaxtime_set(conhdl, 0); + ble_llchmap0_setf(conhdl, + connreq_pdu.chm.map[0] | connreq_pdu.chm.map[1] << 8); + ble_llchmap1_setf(conhdl, + connreq_pdu.chm.map[2] | connreq_pdu.chm.map[3] << 8); + ble_chmap2_pack( + conhdl, llm_util_check_map_validity(connreq_pdu.chm.map, LE_CHNL_MAP_LEN), + connreq_pdu.chm.map[4]); + + GLOBAL_INT_DIS(); + (environ1->evt).non_conn.anchor = element1->timestamp; + (environ1->evt).non_conn.end_ts = CLK_ADD_2( + element1->timestamp, (environ1->evt).non_conn.window / SLOT_SIZE); + (environ1->evt).non_conn.initiate = true; + (environ1->evt).non_conn.connect_req_sent = false; + element1->duration_min = LLD_EVT_FRAME_DURATION; + GLOBAL_INT_RES(); + + return element1; +} |
