1 /* 2 * Copyright (c) 2018-2019 Nordic Semiconductor ASA 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #include <zephyr/toolchain.h> 8 #include <zephyr/types.h> 9 10 #include "hal/ccm.h" 11 #include "hal/radio.h" 12 13 #include "util/memq.h" 14 15 #include "pdu_vendor.h" 16 #include "pdu.h" 17 18 #include "lll.h" 19 20 static uint8_t latency_min = (uint8_t) -1; 21 static uint8_t latency_max; 22 static uint8_t latency_prev; 23 static uint8_t cputime_min = (uint8_t) -1; 24 static uint8_t cputime_max; 25 static uint8_t cputime_prev; 26 static uint32_t timestamp_latency; 27 lll_prof_latency_capture(void)28void lll_prof_latency_capture(void) 29 { 30 /* sample the packet timer, use it to calculate ISR latency 31 * and generate the profiling event at the end of the ISR. 32 */ 33 radio_tmr_sample(); 34 } 35 36 #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) 37 static uint32_t timestamp_radio_end; 38 lll_prof_radio_end_backup(void)39uint32_t lll_prof_radio_end_backup(void) 40 { 41 /* PA enable is overwriting packet end used in ISR profiling, hence 42 * back it up for later use. 43 */ 44 timestamp_radio_end = radio_tmr_end_get(); 45 46 return timestamp_radio_end; 47 } 48 #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ 49 lll_prof_cputime_capture(void)50void lll_prof_cputime_capture(void) 51 { 52 /* get the ISR latency sample */ 53 timestamp_latency = radio_tmr_sample_get(); 54 55 /* sample the packet timer again, use it to calculate ISR execution time 56 * and use it in profiling event 57 */ 58 radio_tmr_sample(); 59 } 60 lll_prof_send(void)61void lll_prof_send(void) 62 { 63 uint8_t latency, cputime, prev; 64 uint8_t chg = 0U; 65 66 /* calculate the elapsed time in us since on-air radio packet end 67 * to ISR entry 68 */ 69 #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) 70 latency = timestamp_latency - timestamp_radio_end; 71 #else /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ 72 latency = timestamp_latency - radio_tmr_end_get(); 73 #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ 74 75 /* check changes in min, avg and max of latency */ 76 if (latency > latency_max) { 77 latency_max = latency; 78 chg = 1U; 79 } 80 if (latency < latency_min) { 81 latency_min = latency; 82 chg = 1U; 83 } 84 85 /* check for +/- 1us change */ 86 prev = ((uint16_t)latency_prev + latency) >> 1; 87 if (prev != latency_prev) { 88 latency_prev = latency; 89 chg = 1U; 90 } 91 92 /* calculate the elapsed time in us since ISR entry */ 93 cputime = radio_tmr_sample_get() - timestamp_latency; 94 95 /* check changes in min, avg and max */ 96 if (cputime > cputime_max) { 97 cputime_max = cputime; 98 chg = 1U; 99 } 100 101 if (cputime < cputime_min) { 102 cputime_min = cputime; 103 chg = 1U; 104 } 105 106 /* check for +/- 1us change */ 107 prev = ((uint16_t)cputime_prev + cputime) >> 1; 108 if (prev != cputime_prev) { 109 cputime_prev = cputime; 110 chg = 1U; 111 } 112 113 /* generate event if any change */ 114 if (chg) { 115 struct node_rx_pdu *rx; 116 117 /* NOTE: enqueue only if rx buffer available, else ignore */ 118 rx = ull_pdu_rx_alloc_peek(3); 119 if (rx) { 120 struct pdu_data *pdu; 121 struct profile *p; 122 123 ull_pdu_rx_alloc(); 124 125 rx->hdr.type = NODE_RX_TYPE_PROFILE; 126 rx->hdr.handle = 0xFFFF; 127 128 pdu = (void *)rx->pdu; 129 p = &pdu->profile; 130 p->lcur = latency; 131 p->lmin = latency_min; 132 p->lmax = latency_max; 133 p->cur = cputime; 134 p->min = cputime_min; 135 p->max = cputime_max; 136 137 ull_rx_put_sched(rx->hdr.link, rx); 138 } 139 } 140 } 141