Bluetooth: Controller: replace work with mayfly

This commit introduces a very light-weight and lock-less
scheduling of the Controller's deferred function calls
called the Mayfly.

Earlier work implementation used in the Controller had an
O(n) to schedule a function in a linked list that used IRQ
lock during modification of the linked list in the
Controller's ISR executions.

Mayfly is a compile time configurable matrix of queues
where an execution context-safe queue exists between two
execution context, one being the caller and the second
being the callee. Callee(s) are run in a software interrupt
but can also be run in an OS thread.

There are minor clean ups too in this commit related to
folder structure.

Change-id: I5ff44dcee6679d2f5ce9e8437d98d6c868782f3d
Signed-off-by: Vinayak Chettimada <vinayak.kariappa.chettimada@nordicsemi.no>
This commit is contained in:
Vinayak Chettimada 2016-12-21 06:21:13 +01:00 committed by Johan Hedberg
commit d5d473b0f8
30 changed files with 1046 additions and 667 deletions

View file

@ -1,15 +1,16 @@
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/util ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/util
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/hal ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/hal
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/ticker
ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/ll ccflags-$(CONFIG_BLUETOOTH_CONTROLLER) += -I$(srctree)/subsys/bluetooth/controller/ll
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/mem.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/mem.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/memq.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/memq.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/work.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/mayfly.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/util.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += util/util.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/rtc.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/nrf5/cntr.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/rand.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/nrf5/rand.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/ecb.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/nrf5/ecb.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/radio.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hal/nrf5/radio.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ticker.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ticker/ticker.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ctrl.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ctrl.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ll.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += ll/ll.o
obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hci/hci_driver.o obj-$(CONFIG_BLUETOOTH_CONTROLLER) += hci/hci_driver.o

View file

@ -18,8 +18,6 @@
#ifndef _CCM_H_ #ifndef _CCM_H_
#define _CCM_H_ #define _CCM_H_
#include <toolchain.h>
struct ccm { struct ccm {
uint8_t key[16]; uint8_t key[16];
uint64_t counter; uint64_t counter;

View file

@ -15,13 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef _RTC_H_ #ifndef _CNTR_H_
#define _RTC_H_ #define _CNTR_H_
void rtc_init(void); void cntr_init(void);
uint32_t rtc_start(void); uint32_t cntr_start(void);
uint32_t rtc_stop(void); uint32_t cntr_stop(void);
uint32_t rtc_tick_get(void); uint32_t cntr_cnt_get(void);
uint32_t rtc_compare_set(uint8_t instance, uint32_t value); void cntr_cmp_set(uint8_t cmp, uint32_t value);
#endif /* _RTC_H_ */ #endif /* _CNTR_H_ */

View file

@ -18,8 +18,6 @@
#ifndef _CPU_H_ #ifndef _CPU_H_
#define _CPU_H_ #define _CPU_H_
#include "nrf.h"
static inline void cpu_sleep(void) static inline void cpu_sleep(void)
{ {
__WFE(); __WFE();

View file

@ -18,8 +18,6 @@
#ifndef _DEBUG_H_ #ifndef _DEBUG_H_
#define _DEBUG_H_ #define _DEBUG_H_
#include <bluetooth/log.h>
#ifdef CONFIG_BLUETOOTH_CONTROLLER_ASSERT_HANDLER #ifdef CONFIG_BLUETOOTH_CONTROLLER_ASSERT_HANDLER
void bt_controller_assert_handle(char *file, uint32_t line); void bt_controller_assert_handle(char *file, uint32_t line);
#define LL_ASSERT(cond) if (!(cond)) { \ #define LL_ASSERT(cond) if (!(cond)) { \

View file

@ -38,7 +38,7 @@ void ecb_encrypt(uint8_t const *const key_le,
uint8_t * const cipher_text_le, uint8_t * const cipher_text_le,
uint8_t * const cipher_text_be); uint8_t * const cipher_text_be);
uint32_t ecb_encrypt_nonblocking(struct ecb *ecb); uint32_t ecb_encrypt_nonblocking(struct ecb *ecb);
void ecb_isr(void); void isr_ecb(void *param);
uint32_t ecb_ut(void); uint32_t ecb_ut(void);

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _HAL_WORK_H_
#define _HAL_WORK_H_
#include "nrf.h"
#define WORK_TICKER_WORKER0_IRQ RTC0_IRQn
#define WORK_TICKER_JOB0_IRQ SWI4_IRQn
#define WORK_TICKER_WORKER1_IRQ SWI5_IRQn
#define WORK_TICKER_JOB1_IRQ SWI5_IRQn
#define WORK_TICKER_WORKER0_IRQ_PRIORITY 0
#define WORK_TICKER_JOB0_IRQ_PRIORITY 0
#define WORK_TICKER_WORKER1_IRQ_PRIORITY 2
#define WORK_TICKER_JOB1_IRQ_PRIORITY 2
#endif /* _HAL_WORK_H_ */

View file

@ -15,27 +15,30 @@
* limitations under the License. * limitations under the License.
*/ */
#include "nrf.h" #include <soc.h>
#include "cntr.h"
#include <bluetooth/log.h>
#include "debug.h" #include "debug.h"
/* RTC instance to use */ #ifndef NRF_RTC
#define NRF_RTC NRF_RTC0 #define NRF_RTC NRF_RTC0
#endif
static uint8_t _rtc_refcount; static uint8_t _refcount;
void rtc_init(void) void cntr_init(void)
{ {
NRF_RTC->PRESCALER = 0; NRF_RTC->PRESCALER = 0;
NRF_RTC->EVTENSET = NRF_RTC->EVTENSET = (RTC_EVTENSET_COMPARE0_Msk |
(RTC_EVTENSET_COMPARE0_Msk | RTC_EVTENSET_COMPARE1_Msk); RTC_EVTENSET_COMPARE1_Msk);
NRF_RTC->INTENSET = NRF_RTC->INTENSET = (RTC_INTENSET_COMPARE0_Msk |
(RTC_INTENSET_COMPARE0_Msk | RTC_INTENSET_COMPARE1_Msk); RTC_INTENSET_COMPARE1_Msk);
} }
uint32_t rtc_start(void) uint32_t cntr_start(void)
{ {
if (_rtc_refcount++) { if (_refcount++) {
return 1; return 1;
} }
@ -44,11 +47,11 @@ uint32_t rtc_start(void)
return 0; return 0;
} }
uint32_t rtc_stop(void) uint32_t cntr_stop(void)
{ {
LL_ASSERT(_rtc_refcount); LL_ASSERT(_refcount);
if (--_rtc_refcount) { if (--_refcount) {
return 1; return 1;
} }
@ -57,12 +60,12 @@ uint32_t rtc_stop(void)
return 0; return 0;
} }
uint32_t rtc_tick_get(void) uint32_t cntr_cnt_get(void)
{ {
return NRF_RTC->COUNTER; return NRF_RTC->COUNTER;
} }
void rtc_compare_set(uint8_t instance, uint32_t value) void cntr_cmp_set(uint8_t cmp, uint32_t value)
{ {
NRF_RTC->CC[instance] = value; NRF_RTC->CC[cmp] = value;
} }

View file

@ -19,8 +19,10 @@
#include <soc.h> #include <soc.h>
#include "mem.h" #include "mem.h"
#include "ecb.h" #include "ecb.h"
#include <bluetooth/log.h>
#include "debug.h" #include "debug.h"
void ecb_encrypt(uint8_t const *const key_le, void ecb_encrypt(uint8_t const *const key_le,
@ -102,8 +104,10 @@ static void ecb_cleanup(void)
irq_disable(ECB_IRQn); irq_disable(ECB_IRQn);
} }
void ecb_isr(void) void isr_ecb(void *param)
{ {
ARG_UNUSED(param);
if (NRF_ECB->EVENTS_ERRORECB) { if (NRF_ECB->EVENTS_ERRORECB) {
struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR; struct ecb *ecb = (struct ecb *)NRF_ECB->ECBDATAPTR;

View file

@ -15,11 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
#include <soc.h> #include <soc.h>
#include <misc/util.h>
#include "hal_work.h" #include "util.h"
#include "mem.h"
#include "defines.h" #include "pdu.h"
#include "ccm.h" #include "ccm.h"
#include "radio.h" #include "radio.h"
@ -33,8 +32,10 @@
static radio_isr_fp sfp_radio_isr; static radio_isr_fp sfp_radio_isr;
void radio_isr(void) void isr_radio(void *param)
{ {
ARG_UNUSED(param);
if (sfp_radio_isr) { if (sfp_radio_isr) {
sfp_radio_isr(); sfp_radio_isr();
} }
@ -215,8 +216,8 @@ uint32_t radio_crc_is_valid(void)
return NRF_RADIO->CRCSTATUS; return NRF_RADIO->CRCSTATUS;
} }
static uint8_t ALIGNED(4) _pkt_empty[RADIO_EMPDU_SIZE_MAX]; static uint8_t MALIGN(4) _pkt_empty[RADIO_EMPDU_SIZE_MAX];
static uint8_t ALIGNED(4) _pkt_scratch[ static uint8_t MALIGN(4) _pkt_scratch[
((RADIO_PDU_LEN_MAX + 3) > RADIO_ACPDU_SIZE_MAX) ? ((RADIO_PDU_LEN_MAX + 3) > RADIO_ACPDU_SIZE_MAX) ?
(RADIO_PDU_LEN_MAX + 3) : RADIO_ACPDU_SIZE_MAX]; (RADIO_PDU_LEN_MAX + 3) : RADIO_ACPDU_SIZE_MAX];
@ -431,7 +432,7 @@ uint32_t radio_tmr_sample_get(void)
return NRF_TIMER0->CC[3]; return NRF_TIMER0->CC[3];
} }
static uint8_t ALIGNED(4) _ccm_scratch[(RADIO_PDU_LEN_MAX - 4) + 16]; static uint8_t MALIGN(4) _ccm_scratch[(RADIO_PDU_LEN_MAX - 4) + 16];
void *radio_ccm_rx_pkt_set(struct ccm *ccm, void *pkt) void *radio_ccm_rx_pkt_set(struct ccm *ccm, void *pkt)
{ {
@ -527,7 +528,7 @@ uint32_t radio_ccm_mic_is_valid(void)
return NRF_CCM->MICSTATUS; return NRF_CCM->MICSTATUS;
} }
static uint8_t ALIGNED(4) _aar_scratch[3]; static uint8_t MALIGN(4) _aar_scratch[3];
void radio_ar_configure(uint32_t nirk, void *irk) void radio_ar_configure(uint32_t nirk, void *irk)
{ {

View file

@ -19,6 +19,7 @@
#include "rand.h" #include "rand.h"
#include <bluetooth/log.h>
#include "debug.h" #include "debug.h"
#define RAND_RESERVED (4) #define RAND_RESERVED (4)
@ -30,19 +31,20 @@ struct rand {
uint8_t rand[1]; uint8_t rand[1];
}; };
static struct rand *_rand; static struct rand *rng;
void rand_init(uint8_t *context, uint8_t context_len) void rand_init(uint8_t *context, uint8_t context_len)
{ {
LL_ASSERT(context_len > sizeof(struct rand)); LL_ASSERT(context_len > sizeof(struct rand));
_rand = (struct rand *)context; rng = (struct rand *)context;
_rand->count = context_len - sizeof(struct rand) + 1; rng->count = context_len - sizeof(struct rand) + 1;
_rand->first = _rand->last = 0; rng->first = rng->last = 0;
NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk; NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk;
NRF_RNG->EVENTS_VALRDY = 0; NRF_RNG->EVENTS_VALRDY = 0;
NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk; NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk;
NRF_RNG->TASKS_START = 1; NRF_RNG->TASKS_START = 1;
} }
@ -52,30 +54,30 @@ uint32_t rand_get(uint8_t octets, uint8_t *rand)
uint8_t first; uint8_t first;
while (octets) { while (octets) {
if (_rand->first == _rand->last) { if (rng->first == rng->last) {
break; break;
} }
rand[--octets] = _rand->rand[_rand->first]; rand[--octets] = rng->rand[rng->first];
first = _rand->first + 1; first = rng->first + 1;
if (first == _rand->count) { if (first == rng->count) {
first = 0; first = 0;
} }
_rand->first = first; rng->first = first;
} }
reserved = RAND_RESERVED; reserved = RAND_RESERVED;
first = _rand->first; first = rng->first;
while (reserved--) { while (reserved--) {
if (first == _rand->last) { if (first == rng->last) {
NRF_RNG->TASKS_START = 1; NRF_RNG->TASKS_START = 1;
break; break;
} }
first++; first++;
if (first == _rand->count) { if (first == rng->count) {
first = 0; first = 0;
} }
} }
@ -83,17 +85,19 @@ uint32_t rand_get(uint8_t octets, uint8_t *rand)
return octets; return octets;
} }
void rng_isr(void) void isr_rand(void *param)
{ {
ARG_UNUSED(param);
if (NRF_RNG->EVENTS_VALRDY) { if (NRF_RNG->EVENTS_VALRDY) {
uint8_t last; uint8_t last;
last = _rand->last + 1; last = rng->last + 1;
if (last == _rand->count) { if (last == rng->count) {
last = 0; last = 0;
} }
if (last == _rand->first) { if (last == rng->first) {
/* this condition should not happen /* this condition should not happen
* , but due to probable bug in HW * , but due to probable bug in HW
* , new value could be generated * , new value could be generated
@ -105,17 +109,17 @@ void rng_isr(void)
return; return;
} }
_rand->rand[_rand->last] = NRF_RNG->VALUE; rng->rand[rng->last] = NRF_RNG->VALUE;
_rand->last = last; rng->last = last;
last = _rand->last + 1; last = rng->last + 1;
if (last == _rand->count) { if (last == rng->count) {
last = 0; last = 0;
} }
NRF_RNG->EVENTS_VALRDY = 0; NRF_RNG->EVENTS_VALRDY = 0;
if (last == _rand->first) { if (last == rng->first) {
NRF_RNG->TASKS_STOP = 1; NRF_RNG->TASKS_STOP = 1;
} }
} }

View file

@ -37,7 +37,7 @@
typedef void (*radio_isr_fp) (void); typedef void (*radio_isr_fp) (void);
void radio_isr(void); void isr_radio(void *param);
void radio_isr_set(radio_isr_fp fp_radio_isr); void radio_isr_set(radio_isr_fp fp_radio_isr);
void radio_reset(void); void radio_reset(void);

View file

@ -20,6 +20,6 @@
void rand_init(uint8_t *context, uint8_t context_len); void rand_init(uint8_t *context, uint8_t context_len);
uint32_t rand_get(uint8_t octets, uint8_t *rand); uint32_t rand_get(uint8_t octets, uint8_t *rand);
void rng_isr(void); void isr_rand(void *param);
#endif /* _RAND_H_ */ #endif /* _RAND_H_ */

View file

@ -18,18 +18,20 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <soc.h>
#include <toolchain.h> #include <toolchain.h>
#include <errno.h> #include <errno.h>
#include <misc/byteorder.h>
#include <bluetooth/hci.h> #include <bluetooth/hci.h>
#include <bluetooth/buf.h> #include <bluetooth/buf.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
#include <misc/byteorder.h>
#include "defines.h" #include "util.h"
#include "ticker.h"
#include "mem.h" #include "mem.h"
#include "rand.h" #include "ticker.h"
#include "cpu.h" #include "cpu.h"
#include "rand.h"
#include "ecb.h" #include "ecb.h"
#include "ccm.h" #include "ccm.h"
#include "radio.h" #include "radio.h"
@ -38,6 +40,7 @@
#include "ll.h" #include "ll.h"
#include "hci_internal.h" #include "hci_internal.h"
#include <bluetooth/log.h>
#include "debug.h" #include "debug.h"
/* opcode of the HCI command currently being processed. The opcode is stored /* opcode of the HCI command currently being processed. The opcode is stored

View file

@ -38,14 +38,18 @@
#include <drivers/clock_control/nrf5_clock_control.h> #include <drivers/clock_control/nrf5_clock_control.h>
#endif #endif
#include "util/defines.h" #include "util/config.h"
#include "util/work.h" #include "util/mayfly.h"
#include "util/util.h"
#include "util/mem.h"
#include "hal/rand.h" #include "hal/rand.h"
#include "hal/ccm.h" #include "hal/ccm.h"
#include "hal/radio.h" #include "hal/radio.h"
#include "hal/hal_rtc.h" #include "hal/cntr.h"
#include "hal/cpu.h" #include "hal/cpu.h"
#include "ll/ticker.h" #include "ticker/ticker.h"
#include "ll/pdu.h"
#include "ll/ctrl.h"
#include "ll/ctrl_internal.h" #include "ll/ctrl_internal.h"
#include "hci_internal.h" #include "hci_internal.h"
@ -61,12 +65,13 @@
#define HCI_SCO 0x03 #define HCI_SCO 0x03
#define HCI_EVT 0x04 #define HCI_EVT 0x04
static uint8_t ALIGNED(4) _rand_context[3 + 4 + 1]; static uint8_t MALIGN(4) _rand_context[3 + 4 + 1];
static uint8_t ALIGNED(4) _ticker_nodes[RADIO_TICKER_NODES][TICKER_NODE_T_SIZE]; static uint8_t MALIGN(4) _ticker_nodes[RADIO_TICKER_NODES][TICKER_NODE_T_SIZE];
static uint8_t ALIGNED(4) _ticker_users[RADIO_TICKER_USERS][TICKER_USER_T_SIZE]; static uint8_t MALIGN(4) _ticker_users[MAYFLY_CALLER_COUNT]
static uint8_t ALIGNED(4) _ticker_user_ops[RADIO_TICKER_USER_OPS] [TICKER_USER_T_SIZE];
static uint8_t MALIGN(4) _ticker_user_ops[RADIO_TICKER_USER_OPS]
[TICKER_USER_OP_T_SIZE]; [TICKER_USER_OP_T_SIZE];
static uint8_t ALIGNED(4) _radio[LL_MEM_TOTAL]; static uint8_t MALIGN(4) _radio[LL_MEM_TOTAL];
static K_SEM_DEFINE(sem_recv, 0, UINT_MAX); static K_SEM_DEFINE(sem_recv, 0, UINT_MAX);
static BT_STACK_NOINIT(recv_thread_stack, static BT_STACK_NOINIT(recv_thread_stack,
@ -96,6 +101,63 @@ int bt_rand(void *buf, size_t len)
} }
#endif #endif
void mayfly_enable(uint8_t caller_id, uint8_t callee_id, uint8_t enable)
{
(void)caller_id;
LL_ASSERT(callee_id == MAYFLY_CALL_ID_1);
if (enable) {
irq_enable(SWI4_IRQn);
} else {
irq_disable(SWI4_IRQn);
}
}
uint32_t mayfly_is_enabled(uint8_t caller_id, uint8_t callee_id)
{
(void)caller_id;
if (callee_id == MAYFLY_CALL_ID_0) {
return irq_is_enabled(RTC0_IRQn);
} else if (callee_id == MAYFLY_CALL_ID_1) {
return irq_is_enabled(SWI4_IRQn);
}
LL_ASSERT(0);
return 0;
}
uint32_t mayfly_prio_is_equal(uint8_t caller_id, uint8_t callee_id)
{
return (caller_id == callee_id) ||
((caller_id == MAYFLY_CALL_ID_0) &&
(callee_id == MAYFLY_CALL_ID_1)) ||
((caller_id == MAYFLY_CALL_ID_1) &&
(callee_id == MAYFLY_CALL_ID_0));
}
void mayfly_pend(uint8_t caller_id, uint8_t callee_id)
{
(void)caller_id;
switch (callee_id) {
case MAYFLY_CALL_ID_0:
_NvicIrqPend(RTC0_IRQn);
break;
case MAYFLY_CALL_ID_1:
_NvicIrqPend(SWI4_IRQn);
break;
case MAYFLY_CALL_ID_PROGRAM:
default:
LL_ASSERT(0);
break;
}
}
void radio_active_callback(uint8_t active) void radio_active_callback(uint8_t active)
{ {
} }
@ -107,7 +169,7 @@ void radio_event_callback(void)
static void radio_nrf5_isr(void *arg) static void radio_nrf5_isr(void *arg)
{ {
radio_isr(); isr_radio(arg);
} }
static void rtc0_nrf5_isr(void *arg) static void rtc0_nrf5_isr(void *arg)
@ -132,22 +194,17 @@ static void rtc0_nrf5_isr(void *arg)
ticker_trigger(1); ticker_trigger(1);
} }
work_run(RTC0_IRQn); mayfly_run(MAYFLY_CALL_ID_0);
} }
static void rng_nrf5_isr(void *arg) static void rng_nrf5_isr(void *arg)
{ {
rng_isr(); isr_rand(arg);
} }
static void swi4_nrf5_isr(void *arg) static void swi4_nrf5_isr(void *arg)
{ {
work_run(NRF5_IRQ_SWI4_IRQn); mayfly_run(MAYFLY_CALL_ID_1);
}
static void swi5_nrf5_isr(void *arg)
{
work_run(NRF5_IRQ_SWI5_IRQn);
} }
static void recv_thread(void *p1, void *p2, void *p3) static void recv_thread(void *p1, void *p2, void *p3)
@ -305,20 +362,18 @@ static int hci_driver_open(void)
clock_control_on(clk_k32, (void *)CLOCK_CONTROL_NRF5_K32SRC); clock_control_on(clk_k32, (void *)CLOCK_CONTROL_NRF5_K32SRC);
/* TODO: bind and use counter driver */ /* TODO: bind and use counter driver */
rtc_init(); cntr_init();
_ticker_users[RADIO_TICKER_USER_ID_WORKER][0] = mayfly_init();
RADIO_TICKER_USER_WORKER_OPS;
_ticker_users[RADIO_TICKER_USER_ID_JOB][0] = _ticker_users[MAYFLY_CALL_ID_0][0] = RADIO_TICKER_USER_WORKER_OPS;
RADIO_TICKER_USER_JOB_OPS; _ticker_users[MAYFLY_CALL_ID_1][0] = RADIO_TICKER_USER_JOB_OPS;
_ticker_users[RADIO_TICKER_USER_ID_APP][0] = _ticker_users[MAYFLY_CALL_ID_2][0] = 0;
RADIO_TICKER_USER_APP_OPS; _ticker_users[MAYFLY_CALL_ID_PROGRAM][0] = RADIO_TICKER_USER_APP_OPS;
ticker_init(RADIO_TICKER_INSTANCE_ID_RADIO, RADIO_TICKER_NODES, ticker_init(RADIO_TICKER_INSTANCE_ID_RADIO, RADIO_TICKER_NODES,
&_ticker_nodes[0] &_ticker_nodes[0], MAYFLY_CALLER_COUNT, &_ticker_users[0],
, RADIO_TICKER_USERS, &_ticker_users[0] RADIO_TICKER_USER_OPS, &_ticker_user_ops[0]);
, RADIO_TICKER_USER_OPS, &_ticker_user_ops[0]
);
clk_m16 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_M16SRC_DRV_NAME); clk_m16 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_M16SRC_DRV_NAME);
if (!clk_m16) { if (!clk_m16) {
@ -341,12 +396,10 @@ static int hci_driver_open(void)
IRQ_CONNECT(NRF5_IRQ_RTC0_IRQn, 0, rtc0_nrf5_isr, 0, 0); IRQ_CONNECT(NRF5_IRQ_RTC0_IRQn, 0, rtc0_nrf5_isr, 0, 0);
IRQ_CONNECT(NRF5_IRQ_RNG_IRQn, 1, rng_nrf5_isr, 0, 0); IRQ_CONNECT(NRF5_IRQ_RNG_IRQn, 1, rng_nrf5_isr, 0, 0);
IRQ_CONNECT(NRF5_IRQ_SWI4_IRQn, 0, swi4_nrf5_isr, 0, 0); IRQ_CONNECT(NRF5_IRQ_SWI4_IRQn, 0, swi4_nrf5_isr, 0, 0);
IRQ_CONNECT(NRF5_IRQ_SWI5_IRQn, 1, swi5_nrf5_isr, 0, 0);
irq_enable(NRF5_IRQ_RADIO_IRQn); irq_enable(NRF5_IRQ_RADIO_IRQn);
irq_enable(NRF5_IRQ_RTC0_IRQn); irq_enable(NRF5_IRQ_RTC0_IRQn);
irq_enable(NRF5_IRQ_RNG_IRQn); irq_enable(NRF5_IRQ_RNG_IRQn);
irq_enable(NRF5_IRQ_SWI4_IRQn); irq_enable(NRF5_IRQ_SWI4_IRQn);
irq_enable(NRF5_IRQ_SWI5_IRQn);
k_thread_spawn(recv_thread_stack, sizeof(recv_thread_stack), k_thread_spawn(recv_thread_stack, sizeof(recv_thread_stack),
recv_thread, NULL, NULL, NULL, K_PRIO_COOP(7), 0, recv_thread, NULL, NULL, NULL, K_PRIO_COOP(7), 0,

View file

@ -15,30 +15,35 @@
* limitations under the License. * limitations under the License.
*/ */
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include <string.h> #include <string.h>
#include <misc/util.h> #include <soc.h>
#include <device.h> #include <device.h>
#include <clock_control.h> #include <clock_control.h>
#include <bluetooth/hci.h>
#include <misc/util.h>
#include "hal_work.h"
#include "defines.h"
#include "cpu.h" #include "cpu.h"
#include "work.h"
#include "rand.h" #include "rand.h"
#include "ticker.h"
#include "mem.h"
#include "memq.h"
#include "util.h"
#include "ecb.h" #include "ecb.h"
#include "ccm.h" #include "ccm.h"
#include "radio.h" #include "radio.h"
#include "mem.h"
#include "memq.h"
#include "mayfly.h"
#include "util.h"
#include "ticker.h"
#include "pdu.h" #include "pdu.h"
#include "ctrl.h"
#include "ctrl_internal.h" #include "ctrl_internal.h"
#include "config.h"
#include <bluetooth/log.h>
#include "debug.h" #include "debug.h"
#define RADIO_PREAMBLE_TO_ADDRESS_US 40 #define RADIO_PREAMBLE_TO_ADDRESS_US 40
@ -331,16 +336,16 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max,
_radio.link_rx_data_quota = rx_count_max; _radio.link_rx_data_quota = rx_count_max;
/* initialise rx queue memory */ /* initialise rx queue memory */
_radio.packet_rx = (struct radio_pdu_node_rx **)mem_radio; _radio.packet_rx = (void *)mem_radio;
mem_radio += mem_radio +=
(sizeof(struct radio_pdu_node_rx *)*_radio.packet_rx_count); (sizeof(struct radio_pdu_node_rx *)*_radio.packet_rx_count);
/* initialise tx queue memory */ /* initialise tx queue memory */
_radio.pkt_tx = (struct pdu_data_q_tx *)mem_radio; _radio.pkt_tx = (void *)mem_radio;
mem_radio += (sizeof(struct pdu_data_q_tx) * _radio.packet_tx_count); mem_radio += (sizeof(struct pdu_data_q_tx) * _radio.packet_tx_count);
/* initialise tx release queue memory */ /* initialise tx release queue memory */
_radio.pkt_release = (struct pdu_data_q_tx *)mem_radio; _radio.pkt_release = (void *)mem_radio;
mem_radio += (sizeof(struct pdu_data_q_tx) * _radio.packet_tx_count); mem_radio += (sizeof(struct pdu_data_q_tx) * _radio.packet_tx_count);
/* initialise rx memory size and count */ /* initialise rx memory size and count */
@ -349,12 +354,12 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max,
(offsetof(struct pdu_data, payload) + (offsetof(struct pdu_data, payload) +
_radio.packet_data_octets_max)) { _radio.packet_data_octets_max)) {
_radio.packet_rx_data_pool_size = _radio.packet_rx_data_pool_size =
(ALIGN4(offsetof(struct radio_pdu_node_rx, pdu_data) + (MROUND(offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_data, payload) + offsetof(struct pdu_data, payload) +
_radio.packet_data_octets_max) * rx_count_max); _radio.packet_data_octets_max) * rx_count_max);
} else { } else {
_radio.packet_rx_data_pool_size = _radio.packet_rx_data_pool_size =
(ALIGN4(offsetof(struct radio_pdu_node_rx, pdu_data) + (MROUND(offsetof(struct radio_pdu_node_rx, pdu_data) +
(RADIO_ACPDU_SIZE_MAX + 1)) * rx_count_max); (RADIO_ACPDU_SIZE_MAX + 1)) * rx_count_max);
} }
_radio.packet_rx_data_size = PACKET_RX_DATA_SIZE_MIN; _radio.packet_rx_data_size = PACKET_RX_DATA_SIZE_MIN;
@ -376,7 +381,7 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max,
/* initialise tx data memory size and count */ /* initialise tx data memory size and count */
_radio.packet_tx_data_size = _radio.packet_tx_data_size =
ALIGN4(offsetof(struct radio_pdu_node_tx, pdu_data) + MROUND(offsetof(struct radio_pdu_node_tx, pdu_data) +
offsetof(struct pdu_data, payload) + offsetof(struct pdu_data, payload) +
packet_tx_data_size); packet_tx_data_size);
@ -2682,7 +2687,7 @@ static inline void isr_radio_state_close(void)
clock_control_off(_radio.hf_clock, NULL); clock_control_off(_radio.hf_clock, NULL);
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_USER_ID_JOB, 1);
DEBUG_RADIO_CLOSE(0); DEBUG_RADIO_CLOSE(0);
} }
@ -2756,14 +2761,15 @@ static void isr(void)
DEBUG_RADIO_ISR(0); DEBUG_RADIO_ISR(0);
} }
#if (WORK_TICKER_WORKER0_IRQ_PRIORITY == WORK_TICKER_JOB0_IRQ_PRIORITY) #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
static void ticker_job_disable(uint32_t status, void *op_context) static void ticker_job_disable(uint32_t status, void *op_context)
{ {
ARG_UNUSED(status); ARG_UNUSED(status);
ARG_UNUSED(op_context); ARG_UNUSED(op_context);
if (_radio.state != STATE_NONE) { if (_radio.state != STATE_NONE) {
work_disable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_JOB, 0);
} }
} }
#endif #endif
@ -2780,7 +2786,7 @@ static void ticker_success_assert(uint32_t status, void *params)
LL_ASSERT(status == TICKER_STATUS_SUCCESS); LL_ASSERT(status == TICKER_STATUS_SUCCESS);
} }
static void work_radio_active(void *params) static void mayfly_radio_active(void *params)
{ {
static uint8_t s_active; static uint8_t s_active;
@ -2808,9 +2814,9 @@ static void work_radio_active(void *params)
static void event_active(uint32_t ticks_at_expire, uint32_t remainder, static void event_active(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *context) uint16_t lazy, void *context)
{ {
static struct work s_work_radio_active = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, (work_fp) work_radio_active, static struct mayfly s_mfy_radio_active = {0, 0, s_link, (void *)1,
(void *)1}; mayfly_radio_active};
uint32_t retval; uint32_t retval;
ARG_UNUSED(ticks_at_expire); ARG_UNUSED(ticks_at_expire);
@ -2818,15 +2824,17 @@ static void event_active(uint32_t ticks_at_expire, uint32_t remainder,
ARG_UNUSED(lazy); ARG_UNUSED(lazy);
ARG_UNUSED(context); ARG_UNUSED(context);
retval = work_schedule(&s_work_radio_active, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_radio_active);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
static void work_radio_inactive(void *params) static void mayfly_radio_inactive(void *params)
{ {
ARG_UNUSED(params); ARG_UNUSED(params);
work_radio_active(0); mayfly_radio_active(0);
DEBUG_RADIO_CLOSE(0); DEBUG_RADIO_CLOSE(0);
} }
@ -2834,8 +2842,9 @@ static void work_radio_inactive(void *params)
static void event_inactive(uint32_t ticks_at_expire, uint32_t remainder, static void event_inactive(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *context) uint16_t lazy, void *context)
{ {
static struct work s_work_radio_inactive = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, (work_fp) work_radio_inactive, 0}; static struct mayfly s_mfy_radio_inactive = {0, 0, s_link, 0,
mayfly_radio_inactive};
uint32_t retval; uint32_t retval;
ARG_UNUSED(ticks_at_expire); ARG_UNUSED(ticks_at_expire);
@ -2843,11 +2852,13 @@ static void event_inactive(uint32_t ticks_at_expire, uint32_t remainder,
ARG_UNUSED(lazy); ARG_UNUSED(lazy);
ARG_UNUSED(context); ARG_UNUSED(context);
retval = work_schedule(&s_work_radio_inactive, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_radio_inactive);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
static void work_xtal_start(void *params) static void mayfly_xtal_start(void *params)
{ {
ARG_UNUSED(params); ARG_UNUSED(params);
@ -2858,8 +2869,9 @@ static void work_xtal_start(void *params)
static void event_xtal(uint32_t ticks_at_expire, uint32_t remainder, static void event_xtal(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *context) uint16_t lazy, void *context)
{ {
static struct work s_work_xtal_start = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, (work_fp) work_xtal_start, 0 }; static struct mayfly s_mfy_xtal_start = {0, 0, s_link, 0,
mayfly_xtal_start};
uint32_t retval; uint32_t retval;
ARG_UNUSED(ticks_at_expire); ARG_UNUSED(ticks_at_expire);
@ -2867,11 +2879,13 @@ static void event_xtal(uint32_t ticks_at_expire, uint32_t remainder,
ARG_UNUSED(lazy); ARG_UNUSED(lazy);
ARG_UNUSED(context); ARG_UNUSED(context);
retval = work_schedule(&s_work_xtal_start, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_xtal_start);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
static void work_xtal_stop(void *params) static void mayfly_xtal_stop(void *params)
{ {
ARG_UNUSED(params); ARG_UNUSED(params);
@ -2881,32 +2895,36 @@ static void work_xtal_stop(void *params)
} }
#if XTAL_ADVANCED #if XTAL_ADVANCED
static void work_xtal_retain(uint8_t retain) static void mayfly_xtal_retain(uint8_t retain)
{ {
static uint8_t s_xtal_retained; static uint8_t s_xtal_retained;
if (retain) { if (retain) {
if (!s_xtal_retained) { if (!s_xtal_retained) {
static struct work s_work_xtal_start = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, static struct mayfly s_mfy_xtal_start = {0, 0, s_link,
(work_fp) work_xtal_start, 0 }; 0, mayfly_xtal_start};
uint32_t retval; uint32_t retval;
s_xtal_retained = 1; s_xtal_retained = 1;
retval = work_schedule(&s_work_xtal_start, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_xtal_start);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
} else { } else {
if (s_xtal_retained) { if (s_xtal_retained) {
static struct work s_work_xtal_stop = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, static struct mayfly s_mfy_xtal_stop = {0, 0, s_link,
(work_fp) work_xtal_stop, 0 }; 0, mayfly_xtal_stop};
uint32_t retval; uint32_t retval;
s_xtal_retained = 0; s_xtal_retained = 0;
retval = work_schedule(&s_work_xtal_stop, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_xtal_stop);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
} }
@ -2972,7 +2990,7 @@ static uint32_t preempt_calc(struct shdr *hdr, uint8_t ticker_id,
diff += 3; diff += 3;
if (diff > TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US)) { if (diff > TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US)) {
work_xtal_retain(0); mayfly_xtal_retain(0);
prepare_normal_set(hdr, RADIO_TICKER_USER_ID_WORKER, ticker_id); prepare_normal_set(hdr, RADIO_TICKER_USER_ID_WORKER, ticker_id);
@ -2997,7 +3015,7 @@ static uint32_t preempt_calc(struct shdr *hdr, uint8_t ticker_id,
* *
* @todo Detect drift for overlapping tickers. * @todo Detect drift for overlapping tickers.
*/ */
static void work_xtal_stop_calc(void *params) static void mayfly_xtal_stop_calc(void *params)
{ {
uint32_t volatile ticker_status; uint32_t volatile ticker_status;
uint8_t ticker_id; uint8_t ticker_id;
@ -3013,14 +3031,15 @@ static void work_xtal_stop_calc(void *params)
ticker_if_done, (void *)&ticker_status); ticker_if_done, (void *)&ticker_status);
while (ticker_status == TICKER_STATUS_BUSY) { while (ticker_status == TICKER_STATUS_BUSY) {
ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO); ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
RADIO_TICKER_USER_ID_JOB);
} }
LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS); LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS);
if ((ticker_id != 0xff) && if ((ticker_id != 0xff) &&
(ticks_to_expire < TICKER_US_TO_TICKS(10000))) { (ticks_to_expire < TICKER_US_TO_TICKS(10000))) {
work_xtal_retain(1); mayfly_xtal_retain(1);
if (ticker_id >= RADIO_TICKER_ID_ADV) { if (ticker_id >= RADIO_TICKER_ID_ADV) {
#if SCHED_ADVANCED #if SCHED_ADVANCED
@ -3158,7 +3177,7 @@ static void work_xtal_stop_calc(void *params)
#endif /* SCHED_ADVANCED */ #endif /* SCHED_ADVANCED */
} }
} else { } else {
work_xtal_retain(0); mayfly_xtal_retain(0);
if ((ticker_id != 0xff) && (ticker_id >= RADIO_TICKER_ID_ADV)) { if ((ticker_id != 0xff) && (ticker_id >= RADIO_TICKER_ID_ADV)) {
struct shdr *hdr = NULL; struct shdr *hdr = NULL;
@ -3189,10 +3208,10 @@ static void work_xtal_stop_calc(void *params)
#endif /* XTAL_ADVANCED */ #endif /* XTAL_ADVANCED */
#if SCHED_ADVANCED #if SCHED_ADVANCED
static void sched_after_master_free_slot_get(uint8_t user_id, static void sched_after_mstr_free_slot_get(uint8_t user_id,
uint32_t ticks_slot_abs, uint32_t ticks_slot_abs,
uint32_t *ticks_anchor, uint32_t *ticks_anchor,
uint32_t *us_offset) uint32_t *us_offset)
{ {
uint8_t ticker_id; uint8_t ticker_id;
uint8_t ticker_id_prev; uint8_t ticker_id_prev;
@ -3214,7 +3233,8 @@ static void sched_after_master_free_slot_get(uint8_t user_id,
(void *)&ticker_status); (void *)&ticker_status);
while (ticker_status == TICKER_STATUS_BUSY) { while (ticker_status == TICKER_STATUS_BUSY) {
ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO); ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
user_id);
} }
LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS); LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS);
@ -3268,17 +3288,18 @@ static void sched_after_master_free_slot_get(uint8_t user_id,
} }
} }
static void sched_after_master_free_offset_get(uint16_t conn_interval, static void sched_after_mstr_free_offset_get(uint16_t conn_interval,
uint32_t ticks_slot, uint32_t ticks_slot,
uint32_t ticks_anchor, uint32_t ticks_anchor,
uint32_t *win_offset_us) uint32_t *win_offset_us)
{ {
uint32_t ticks_anchor_offset = ticks_anchor; uint32_t ticks_anchor_offset = ticks_anchor;
sched_after_master_free_slot_get(RADIO_TICKER_USER_ID_JOB, sched_after_mstr_free_slot_get(RADIO_TICKER_USER_ID_JOB,
(TICKER_US_TO_TICKS(RADIO_TICKER_XTAL_OFFSET_US) + (TICKER_US_TO_TICKS(
ticks_slot), &ticks_anchor_offset, RADIO_TICKER_XTAL_OFFSET_US) +
win_offset_us); ticks_slot), &ticks_anchor_offset,
win_offset_us);
if (ticks_anchor_offset != ticks_anchor) { if (ticks_anchor_offset != ticks_anchor) {
*win_offset_us += *win_offset_us +=
@ -3295,23 +3316,23 @@ static void sched_after_master_free_offset_get(uint16_t conn_interval,
} }
} }
static void work_sched_after_master_free_offset_get(void *params) static void mayfly_sched_after_mstr_free_offset_get(void *params)
{ {
sched_after_master_free_offset_get(_radio.observer.conn_interval, sched_after_mstr_free_offset_get(_radio.observer.conn_interval,
_radio.observer.ticks_conn_slot, _radio.observer.ticks_conn_slot,
(uint32_t)params, (uint32_t)params,
&_radio.observer.win_offset_us); &_radio.observer.win_offset_us);
} }
static void work_sched_win_offset_use(void *params) static void mayfly_sched_win_offset_use(void *params)
{ {
struct connection *conn = (struct connection *)params; struct connection *conn = (struct connection *)params;
uint16_t win_offset; uint16_t win_offset;
sched_after_master_free_offset_get(conn->conn_interval, sched_after_mstr_free_offset_get(conn->conn_interval,
conn->hdr.ticks_slot, conn->hdr.ticks_slot,
conn->llcp.connection_update.ticks_ref, conn->llcp.connection_update.ticks_ref,
&conn->llcp.connection_update.win_offset_us); &conn->llcp.connection_update.win_offset_us);
win_offset = conn->llcp.connection_update.win_offset_us / 1250; win_offset = conn->llcp.connection_update.win_offset_us / 1250;
memcpy(conn->llcp.connection_update.pdu_win_offset, &win_offset, memcpy(conn->llcp.connection_update.pdu_win_offset, &win_offset,
@ -3366,7 +3387,8 @@ static void sched_free_win_offset_calc(struct connection *conn_curr,
(void *)&ticker_status); (void *)&ticker_status);
while (ticker_status == TICKER_STATUS_BUSY) { while (ticker_status == TICKER_STATUS_BUSY) {
ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO); ticker_job_sched(RADIO_TICKER_INSTANCE_ID_RADIO,
RADIO_TICKER_USER_ID_JOB);
} }
LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS); LL_ASSERT(ticker_status == TICKER_STATUS_SUCCESS);
@ -3495,7 +3517,7 @@ static void sched_free_win_offset_calc(struct connection *conn_curr,
*offset_max = offset_index; *offset_max = offset_index;
} }
static void work_sched_free_win_offset_calc(void *params) static void mayfly_sched_free_win_offset_calc(void *params)
{ {
struct connection *conn = (struct connection *)params; struct connection *conn = (struct connection *)params;
uint32_t ticks_to_offset_default = 0; uint32_t ticks_to_offset_default = 0;
@ -3518,7 +3540,7 @@ static void work_sched_free_win_offset_calc(void *params)
(uint8_t *)conn->llcp.connection_update.pdu_win_offset); (uint8_t *)conn->llcp.connection_update.pdu_win_offset);
} }
static void work_sched_win_offset_select(void *params) static void mayfly_sched_win_offset_select(void *params)
{ {
#define OFFSET_S_MAX 6 #define OFFSET_S_MAX 6
#define OFFSET_M_MAX 6 #define OFFSET_M_MAX 6
@ -3592,7 +3614,7 @@ static void work_sched_win_offset_select(void *params)
} }
#endif /* SCHED_ADVANCED */ #endif /* SCHED_ADVANCED */
static void work_radio_stop(void *params) static void mayfly_radio_stop(void *params)
{ {
enum state state = (enum state)((uint32_t)params & 0xff); enum state state = (enum state)((uint32_t)params & 0xff);
uint32_t radio_used; uint32_t radio_used;
@ -3615,8 +3637,9 @@ static void work_radio_stop(void *params)
static void event_stop(uint32_t ticks_at_expire, uint32_t remainder, static void event_stop(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *context) uint16_t lazy, void *context)
{ {
static struct work s_work_radio_stop = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, (work_fp) work_radio_stop, 0 }; static struct mayfly s_mfy_radio_stop = {0, 0, s_link, 0,
mayfly_radio_stop};
uint32_t retval; uint32_t retval;
ARG_UNUSED(ticks_at_expire); ARG_UNUSED(ticks_at_expire);
@ -3626,10 +3649,12 @@ static void event_stop(uint32_t ticks_at_expire, uint32_t remainder,
/* Radio state requested (stop or abort) stored in context is supplied /* Radio state requested (stop or abort) stored in context is supplied
* in params. * in params.
*/ */
s_work_radio_stop.params = context; s_mfy_radio_stop.param = context;
/* Stop Radio Tx/Rx */ /* Stop Radio Tx/Rx */
retval = work_schedule(&s_work_radio_stop, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_radio_stop);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
@ -3776,14 +3801,16 @@ static void event_common_prepare(uint32_t ticks_at_expire,
/* calc whether xtal needs to be retained after this event */ /* calc whether xtal needs to be retained after this event */
#if XTAL_ADVANCED #if XTAL_ADVANCED
{ {
static struct work s_work_xtal_stop_calc = { static void *s_link[2];
0, 0, 0, WORK_TICKER_JOB0_IRQ, static struct mayfly s_mfy_xtal_stop_calc = {0, 0, s_link, 0,
(work_fp) work_xtal_stop_calc, 0 }; mayfly_xtal_stop_calc};
uint32_t retval; uint32_t retval;
s_work_xtal_stop_calc.params = (void *)(uint32_t)ticker_id; s_mfy_xtal_stop_calc.param = (void *)(uint32_t)ticker_id;
retval = work_schedule(&s_work_xtal_stop_calc, 1); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_JOB, 1,
&s_mfy_xtal_stop_calc);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
#endif #endif
@ -4064,8 +4091,9 @@ static void event_adv(uint32_t ticks_at_expire, uint32_t remainder,
radio_disable(); radio_disable();
} else } else
#endif #endif
/* Ticker Job Silence */
#if (WORK_TICKER_WORKER0_IRQ_PRIORITY == WORK_TICKER_JOB0_IRQ_PRIORITY) /* Ticker Job Silence */
#if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
{ {
uint32_t ticker_status; uint32_t ticker_status;
@ -4158,9 +4186,10 @@ static void event_obs_prepare(uint32_t ticks_at_expire, uint32_t remainder,
* to be placed * to be placed
*/ */
if (_radio.observer.conn) { if (_radio.observer.conn) {
static struct work _work_sched_after_master_free_offset_get = { static void *s_link[2];
0, 0, 0, WORK_TICKER_JOB0_IRQ, static struct mayfly s_mfy_sched_after_mstr_free_offset_get = {
(work_fp) work_sched_after_master_free_offset_get, 0 }; 0, 0, s_link, 0,
mayfly_sched_after_mstr_free_offset_get};
uint32_t ticks_at_expire_normal = ticks_at_expire; uint32_t ticks_at_expire_normal = ticks_at_expire;
uint32_t retval; uint32_t retval;
@ -4177,11 +4206,12 @@ static void event_obs_prepare(uint32_t ticks_at_expire, uint32_t remainder,
ticks_prepare_to_start); ticks_prepare_to_start);
} }
_work_sched_after_master_free_offset_get.params = s_mfy_sched_after_mstr_free_offset_get.param =
(void *)ticks_at_expire_normal; (void *)ticks_at_expire_normal;
retval = work_schedule(&_work_sched_after_master_free_offset_get, retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
1); RADIO_TICKER_USER_ID_JOB, 1,
&s_mfy_sched_after_mstr_free_offset_get);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
#endif #endif
@ -4267,7 +4297,7 @@ static void event_obs(uint32_t ticks_at_expire, uint32_t remainder,
(ticker_status == TICKER_STATUS_BUSY)); (ticker_status == TICKER_STATUS_BUSY));
/* Ticker Job Silence */ /* Ticker Job Silence */
#if (WORK_TICKER_WORKER0_IRQ_PRIORITY == WORK_TICKER_JOB0_IRQ_PRIORITY) #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
{ {
uint32_t ticker_status; uint32_t ticker_status;
@ -4285,12 +4315,13 @@ static void event_obs(uint32_t ticks_at_expire, uint32_t remainder,
DEBUG_RADIO_START_O(0); DEBUG_RADIO_START_O(0);
} }
static inline void event_conn_update_st_init(struct connection *conn, static inline void
uint16_t event_counter, event_conn_update_st_init(struct connection *conn,
struct pdu_data *pdu_ctrl_tx, uint16_t event_counter,
uint32_t ticks_at_expire, struct pdu_data *pdu_ctrl_tx,
struct work *work_sched_offset, uint32_t ticks_at_expire,
work_fp fp_work_select_or_use) struct mayfly *mayfly_sched_offset,
void (*fp_mayfly_select_or_use)(void *))
{ {
/* move to in progress */ /* move to in progress */
conn->llcp.connection_update.state = LLCP_CONN_STATE_INPROG; conn->llcp.connection_update.state = LLCP_CONN_STATE_INPROG;
@ -4342,16 +4373,18 @@ static inline void event_conn_update_st_init(struct connection *conn,
conn->llcp.connection_update.pdu_win_offset = (uint16_t *) conn->llcp.connection_update.pdu_win_offset = (uint16_t *)
&pdu_ctrl_tx->payload.llctrl.ctrldata.conn_update_req.win_offset; &pdu_ctrl_tx->payload.llctrl.ctrldata.conn_update_req.win_offset;
work_sched_offset->fp = fp_work_select_or_use; mayfly_sched_offset->fp = fp_mayfly_select_or_use;
work_sched_offset->params = (void *)conn; mayfly_sched_offset->param = (void *)conn;
retval = work_schedule(work_sched_offset, 1); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_JOB, 1,
mayfly_sched_offset);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
#else #else
ARG_UNUSED(ticks_at_expire); ARG_UNUSED(ticks_at_expire);
ARG_UNUSED(work_sched_offset); ARG_UNUSED(mayfly_sched_offset);
ARG_UNUSED(fp_work_select_or_use); ARG_UNUSED(fp_mayfly_select_or_use);
#endif #endif
} }
@ -4359,7 +4392,7 @@ static inline void event_conn_update_st_req(struct connection *conn,
uint16_t event_counter, uint16_t event_counter,
struct pdu_data *pdu_ctrl_tx, struct pdu_data *pdu_ctrl_tx,
uint32_t ticks_at_expire, uint32_t ticks_at_expire,
struct work *work_sched_offset) struct mayfly *mayfly_sched_offset)
{ {
/* move to wait for conn_update/rsp/rej */ /* move to wait for conn_update/rsp/rej */
conn->llcp.connection_update.state = LLCP_CONN_STATE_RSP_WAIT; conn->llcp.connection_update.state = LLCP_CONN_STATE_RSP_WAIT;
@ -4411,15 +4444,17 @@ static inline void event_conn_update_st_req(struct connection *conn,
conn->llcp.connection_update.pdu_win_offset = (uint16_t *) conn->llcp.connection_update.pdu_win_offset = (uint16_t *)
&pdu_ctrl_tx->payload.llctrl.ctrldata.conn_param_req.offset0; &pdu_ctrl_tx->payload.llctrl.ctrldata.conn_param_req.offset0;
work_sched_offset->fp = work_sched_free_win_offset_calc; mayfly_sched_offset->fp = mayfly_sched_free_win_offset_calc;
work_sched_offset->params = (void *)conn; mayfly_sched_offset->param = (void *)conn;
retval = work_schedule(work_sched_offset, 1); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_JOB, 1,
mayfly_sched_offset);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
#else #else
ARG_UNUSED(ticks_at_expire); ARG_UNUSED(ticks_at_expire);
ARG_UNUSED(work_sched_offset); ARG_UNUSED(mayfly_sched_offset);
#endif #endif
} }
@ -4490,9 +4525,10 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
(conn->llcp.connection_update.state != (conn->llcp.connection_update.state !=
LLCP_CONN_STATE_RSP_WAIT)) { LLCP_CONN_STATE_RSP_WAIT)) {
#if SCHED_ADVANCED #if SCHED_ADVANCED
static struct work gs_work_sched_offset = { static void *s_link[2];
0, 0, 0, WORK_TICKER_JOB0_IRQ, 0, 0 }; static struct mayfly s_mfy_sched_offset = {0, 0,
work_fp fp_work_select_or_use; s_link, 0, 0 };
void (*fp_mayfly_select_or_use)(void *);
#endif #endif
struct radio_pdu_node_tx *node_tx; struct radio_pdu_node_tx *node_tx;
struct pdu_data *pdu_ctrl_tx; struct pdu_data *pdu_ctrl_tx;
@ -4506,15 +4542,15 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
pdu_ctrl_tx = (struct pdu_data *)node_tx->pdu_data; pdu_ctrl_tx = (struct pdu_data *)node_tx->pdu_data;
#if SCHED_ADVANCED #if SCHED_ADVANCED
fp_work_select_or_use = work_sched_win_offset_use; fp_mayfly_select_or_use = mayfly_sched_win_offset_use;
#endif #endif
state = conn->llcp.connection_update.state; state = conn->llcp.connection_update.state;
if ((state == LLCP_CONN_STATE_RSP) && if ((state == LLCP_CONN_STATE_RSP) &&
(conn->role.master.role == 0)) { (conn->role.master.role == 0)) {
state = LLCP_CONN_STATE_INITIATE; state = LLCP_CONN_STATE_INITIATE;
#if SCHED_ADVANCED #if SCHED_ADVANCED
fp_work_select_or_use = fp_mayfly_select_or_use =
work_sched_win_offset_select; mayfly_sched_win_offset_select;
#endif #endif
} }
@ -4523,18 +4559,18 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
if (conn->role.master.role == 0) { if (conn->role.master.role == 0) {
#if SCHED_ADVANCED #if SCHED_ADVANCED
event_conn_update_st_init(conn, event_conn_update_st_init(conn,
event_counter, event_counter,
pdu_ctrl_tx, pdu_ctrl_tx,
ticks_at_expire, ticks_at_expire,
&gs_work_sched_offset, &s_mfy_sched_offset,
fp_work_select_or_use); fp_mayfly_select_or_use);
#else #else
event_conn_update_st_init(conn, event_conn_update_st_init(conn,
event_counter, event_counter,
pdu_ctrl_tx, pdu_ctrl_tx,
ticks_at_expire, ticks_at_expire,
NULL, NULL,
NULL); NULL);
#endif #endif
break; break;
} }
@ -4546,7 +4582,7 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
event_counter, event_counter,
pdu_ctrl_tx, pdu_ctrl_tx,
ticks_at_expire, ticks_at_expire,
&gs_work_sched_offset); &s_mfy_sched_offset);
#else #else
event_conn_update_st_req(conn, event_conn_update_st_req(conn,
event_counter, event_counter,
@ -4579,7 +4615,7 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
uint16_t conn_interval_old; uint16_t conn_interval_old;
uint16_t conn_interval_new; uint16_t conn_interval_new;
uint16_t latency; uint16_t latency;
uint32_t work_was_enabled; uint32_t mayfly_was_enabled;
/* procedure request acked */ /* procedure request acked */
conn->llcp_ack = conn->llcp_req; conn->llcp_ack = conn->llcp_req;
@ -4728,8 +4764,11 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
/* disable ticker job, in order to chain stop and start /* disable ticker job, in order to chain stop and start
* to avoid RTC being stopped if no tickers active. * to avoid RTC being stopped if no tickers active.
*/ */
work_was_enabled = work_is_enabled(WORK_TICKER_JOB0_IRQ); mayfly_was_enabled =
work_disable(WORK_TICKER_JOB0_IRQ); mayfly_is_enabled(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_JOB);
mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_JOB, 0);
/* start slave/master with new timings */ /* start slave/master with new timings */
ticker_status = ticker_status =
@ -4758,8 +4797,9 @@ static inline uint32_t event_conn_update_prep(struct connection *conn,
(ticker_status == TICKER_STATUS_BUSY)); (ticker_status == TICKER_STATUS_BUSY));
/* enable ticker job, if disabled in this function */ /* enable ticker job, if disabled in this function */
if (work_was_enabled) { if (mayfly_was_enabled) {
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_WORKER,
RADIO_TICKER_USER_ID_JOB, 1);
} }
return 0; return 0;
@ -5204,7 +5244,7 @@ static inline void event_len_prep(struct connection *conn)
if (_radio.observer.conn) { if (_radio.observer.conn) {
free_count_conn++; free_count_conn++;
} }
packet_rx_data_size = ALIGN4(offsetof(struct radio_pdu_node_rx, packet_rx_data_size = MROUND(offsetof(struct radio_pdu_node_rx,
pdu_data) + pdu_data) +
offsetof(struct pdu_data, offsetof(struct pdu_data,
payload) + payload) +
@ -5247,9 +5287,9 @@ static inline void event_len_prep(struct connection *conn)
/* calculate the new rx node size and new count */ /* calculate the new rx node size and new count */
if (conn->max_rx_octets < (RADIO_ACPDU_SIZE_MAX + 1)) { if (conn->max_rx_octets < (RADIO_ACPDU_SIZE_MAX + 1)) {
_radio.packet_rx_data_size = _radio.packet_rx_data_size =
ALIGN4(offsetof(struct radio_pdu_node_rx, MROUND(offsetof(struct radio_pdu_node_rx,
pdu_data) + pdu_data) +
(RADIO_ACPDU_SIZE_MAX + 1)); (RADIO_ACPDU_SIZE_MAX + 1));
} else { } else {
_radio.packet_rx_data_size = _radio.packet_rx_data_size =
packet_rx_data_size; packet_rx_data_size;
@ -5552,8 +5592,8 @@ static void event_slave(uint32_t ticks_at_expire, uint32_t remainder,
} else } else
#endif #endif
/* Ticker Job Silence */ /* Ticker Job Silence */
#if (WORK_TICKER_WORKER0_IRQ_PRIORITY == WORK_TICKER_JOB0_IRQ_PRIORITY) #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
{ {
uint32_t ticker_status; uint32_t ticker_status;
@ -5690,7 +5730,7 @@ static void event_master(uint32_t ticks_at_expire, uint32_t remainder,
#endif #endif
/* Ticker Job Silence */ /* Ticker Job Silence */
#if (WORK_TICKER_WORKER0_IRQ_PRIORITY == WORK_TICKER_JOB0_IRQ_PRIORITY) #if (RADIO_TICKER_USER_ID_WORKER_PRIO == RADIO_TICKER_USER_ID_JOB_PRIO)
{ {
uint32_t ticker_status; uint32_t ticker_status;
@ -5920,12 +5960,14 @@ static struct radio_pdu_node_rx *packet_rx_reserve_get(uint8_t count)
return radio_pdu_node_rx; return radio_pdu_node_rx;
} }
static void event_callback(void) static void packet_rx_callback(void)
{ {
static struct work work_event_callback = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_JOB0_IRQ, (work_fp) radio_event_callback, 0 }; static struct mayfly s_mfy_callback = {0, 0, s_link, 0,
(void *)radio_event_callback};
work_schedule(&work_event_callback, 1); mayfly_enqueue(RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_USER_ID_JOB, 1,
&s_mfy_callback);
} }
static void packet_rx_enqueue(void) static void packet_rx_enqueue(void)
@ -5959,7 +6001,7 @@ static void packet_rx_enqueue(void)
LL_ASSERT(link); LL_ASSERT(link);
/* callback to trigger application action */ /* callback to trigger application action */
event_callback(); packet_rx_callback();
} }
static void packet_tx_enqueue(uint8_t max) static void packet_tx_enqueue(uint8_t max)
@ -6112,7 +6154,7 @@ static void pdu_node_tx_release(uint16_t handle,
_radio.packet_release_last = last; _radio.packet_release_last = last;
/* callback to trigger application action */ /* callback to trigger application action */
event_callback(); packet_rx_callback();
} }
static void connection_release(struct connection *conn) static void connection_release(struct connection *conn)
@ -6122,7 +6164,7 @@ static void connection_release(struct connection *conn)
/* Enable Ticker Job, we are in a radio event which disabled it if /* Enable Ticker Job, we are in a radio event which disabled it if
* worker0 and job0 priority where same. * worker0 and job0 priority where same.
*/ */
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_WORKER, RADIO_TICKER_USER_ID_JOB, 1);
/** @todo correctly stop tickers ensuring crystal and radio active are /** @todo correctly stop tickers ensuring crystal and radio active are
* placed in right states * placed in right states
@ -6243,7 +6285,7 @@ static void terminate_ind_rx_enqueue(struct connection *conn, uint8_t reason)
LL_ASSERT(link); LL_ASSERT(link);
/* callback to trigger application action */ /* callback to trigger application action */
event_callback(); packet_rx_callback();
} }
static uint32_t conn_update(struct connection *conn, static uint32_t conn_update(struct connection *conn,
@ -6687,8 +6729,9 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
uint32_t ticks_xtal_to_start, uint32_t ticks_xtal_to_start,
uint32_t ticks_active_to_start) uint32_t ticks_active_to_start)
{ {
static struct work s_work_radio_inactive = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, (work_fp) work_radio_inactive, 0 }; static struct mayfly s_mfy_radio_inactive = {0, 0, s_link, 0,
mayfly_radio_inactive};
uint32_t volatile ticker_status_event; uint32_t volatile ticker_status_event;
/* Step 2: Is caller before Event? Stop Event */ /* Step 2: Is caller before Event? Stop Event */
@ -6698,14 +6741,16 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
ticker_if_done, (void *)&ticker_status_event); ticker_if_done, (void *)&ticker_status_event);
if (ticker_status_event == TICKER_STATUS_BUSY) { if (ticker_status_event == TICKER_STATUS_BUSY) {
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_JOB, 1);
LL_ASSERT(ticker_status_event != TICKER_STATUS_BUSY); LL_ASSERT(ticker_status_event != TICKER_STATUS_BUSY);
} }
if (ticker_status_event == TICKER_STATUS_SUCCESS) { if (ticker_status_event == TICKER_STATUS_SUCCESS) {
static struct work s_work_xtal_stop = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, (work_fp) work_xtal_stop, 0 }; static struct mayfly s_mfy_xtal_stop = {0, 0, s_link, 0,
mayfly_xtal_stop};
uint32_t volatile ticker_status_pre_event; uint32_t volatile ticker_status_pre_event;
/* Step 2.1: Is caller between Primary and Marker0? /* Step 2.1: Is caller between Primary and Marker0?
@ -6719,7 +6764,8 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
(void *)&ticker_status_pre_event); (void *)&ticker_status_pre_event);
if (ticker_status_pre_event == TICKER_STATUS_BUSY) { if (ticker_status_pre_event == TICKER_STATUS_BUSY) {
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_JOB, 1);
LL_ASSERT(ticker_status_event != TICKER_STATUS_BUSY); LL_ASSERT(ticker_status_event != TICKER_STATUS_BUSY);
} }
@ -6734,14 +6780,19 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
/* radio active asserted, handle deasserting /* radio active asserted, handle deasserting
* here * here
*/ */
retval = work_schedule(&s_work_radio_inactive, retval = mayfly_enqueue(
0); RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_radio_inactive);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} else { } else {
uint32_t retval; uint32_t retval;
/* XTAL started, handle XTAL stop here */ /* XTAL started, handle XTAL stop here */
retval = work_schedule(&s_work_xtal_stop, 0); retval = mayfly_enqueue(
RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_xtal_stop);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} }
} else if (ticker_status_pre_event == TICKER_STATUS_FAILURE) { } else if (ticker_status_pre_event == TICKER_STATUS_FAILURE) {
@ -6750,11 +6801,15 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
/* Step 2.1.2: Deassert Radio Active and XTAL start */ /* Step 2.1.2: Deassert Radio Active and XTAL start */
/* radio active asserted, handle deasserting here */ /* radio active asserted, handle deasserting here */
retval = work_schedule(&s_work_radio_inactive, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_radio_inactive);
LL_ASSERT(!retval); LL_ASSERT(!retval);
/* XTAL started, handle XTAL stop here */ /* XTAL started, handle XTAL stop here */
retval = work_schedule(&s_work_xtal_stop, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_xtal_stop);
LL_ASSERT(!retval); LL_ASSERT(!retval);
} else { } else {
LL_ASSERT(0); LL_ASSERT(0);
@ -6775,7 +6830,8 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
(void *)&ticker_status_stop); (void *)&ticker_status_stop);
if (ticker_status_stop == TICKER_STATUS_BUSY) { if (ticker_status_stop == TICKER_STATUS_BUSY) {
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_JOB, 1);
LL_ASSERT(ticker_status_event != TICKER_STATUS_BUSY); LL_ASSERT(ticker_status_event != TICKER_STATUS_BUSY);
} }
@ -6784,16 +6840,18 @@ static inline void role_active_disable(uint8_t ticker_id_stop,
(ticker_status_stop == TICKER_STATUS_FAILURE)); (ticker_status_stop == TICKER_STATUS_FAILURE));
if (_radio.role != ROLE_NONE) { if (_radio.role != ROLE_NONE) {
static struct work s_work_radio_stop = { 0, 0, 0, static void *s_link[2];
WORK_TICKER_WORKER0_IRQ, static struct mayfly s_mfy_radio_stop = {0, 0, s_link,
(work_fp) work_radio_stop, 0 }; 0, mayfly_radio_stop};
uint32_t retval; uint32_t retval;
/* Radio state STOP is supplied in params */ /* Radio state STOP is supplied in params */
s_work_radio_stop.params = (void *)STATE_STOP; s_mfy_radio_stop.param = (void *)STATE_STOP;
/* Stop Radio Tx/Rx */ /* Stop Radio Tx/Rx */
retval = work_schedule(&s_work_radio_stop, 0); retval = mayfly_enqueue(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_WORKER, 0,
&s_mfy_radio_stop);
LL_ASSERT(!retval); LL_ASSERT(!retval);
/* wait for radio ISR to exit */ /* wait for radio ISR to exit */
@ -6860,7 +6918,8 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
if (ticker_status == TICKER_STATUS_BUSY) { if (ticker_status == TICKER_STATUS_BUSY) {
/* if inside our event, enable Job. */ /* if inside our event, enable Job. */
if (_radio.ticker_id_event == ticker_id_primary) { if (_radio.ticker_id_event == ticker_id_primary) {
work_enable(WORK_TICKER_JOB0_IRQ); mayfly_enable(RADIO_TICKER_USER_ID_JOB,
RADIO_TICKER_USER_ID_JOB, 1);
} }
/** @todo design to avoid this wait */ /** @todo design to avoid this wait */
@ -7156,10 +7215,10 @@ uint32_t radio_scan_enable(uint8_t scan_type, uint8_t init_addr_type,
} }
#if SCHED_ADVANCED #if SCHED_ADVANCED
else { else {
sched_after_master_free_slot_get(RADIO_TICKER_USER_ID_APP, sched_after_mstr_free_slot_get(RADIO_TICKER_USER_ID_APP,
(ticks_slot_offset + (ticks_slot_offset +
_radio.observer.hdr.ticks_slot), _radio.observer.hdr.ticks_slot),
&ticks_anchor, &us_offset); &ticks_anchor, &us_offset);
} }
#endif #endif

View file

@ -18,8 +18,6 @@
#ifndef _CTRL_H_ #ifndef _CTRL_H_
#define _CTRL_H_ #define _CTRL_H_
#include <bluetooth/hci.h>
/***************************************************************************** /*****************************************************************************
* Zephyr Kconfig defined * Zephyr Kconfig defined
****************************************************************************/ ****************************************************************************/
@ -76,9 +74,12 @@
#define RADIO_TICKER_USERS 3 #define RADIO_TICKER_USERS 3
#define RADIO_TICKER_USER_ID_WORKER 0 #define RADIO_TICKER_USER_ID_WORKER TICKER_MAYFLY_CALL_ID_WORKER0
#define RADIO_TICKER_USER_ID_JOB 1 #define RADIO_TICKER_USER_ID_JOB TICKER_MAYFLY_CALL_ID_JOB0
#define RADIO_TICKER_USER_ID_APP 2 #define RADIO_TICKER_USER_ID_APP TICKER_MAYFLY_CALL_ID_PROGRAM
#define RADIO_TICKER_USER_ID_WORKER_PRIO TICKER_MAYFLY_CALL_ID_WORKER0_PRIO
#define RADIO_TICKER_USER_ID_JOB_PRIO TICKER_MAYFLY_CALL_ID_JOB0_PRIO
#define RADIO_TICKER_USER_WORKER_OPS (7 + 1) #define RADIO_TICKER_USER_WORKER_OPS (7 + 1)
#define RADIO_TICKER_USER_JOB_OPS (2 + 1) #define RADIO_TICKER_USER_JOB_OPS (2 + 1)
@ -289,6 +290,7 @@ uint8_t radio_rx_get(struct radio_pdu_node_rx **radio_pdu_node_rx,
void radio_rx_dequeue(void); void radio_rx_dequeue(void);
void radio_rx_mem_release(struct radio_pdu_node_rx **radio_pdu_node_rx); void radio_rx_mem_release(struct radio_pdu_node_rx **radio_pdu_node_rx);
uint8_t radio_rx_fc_set(uint16_t handle, uint8_t fc); uint8_t radio_rx_fc_set(uint16_t handle, uint8_t fc);
uint8_t radio_rx_fc_get(uint16_t *handle);
struct radio_pdu_node_tx *radio_tx_mem_acquire(void); struct radio_pdu_node_tx *radio_tx_mem_acquire(void);
void radio_tx_mem_release(struct radio_pdu_node_tx *pdu_data_node_tx); void radio_tx_mem_release(struct radio_pdu_node_tx *pdu_data_node_tx);
uint32_t radio_tx_mem_enqueue(uint16_t handle, uint32_t radio_tx_mem_enqueue(uint16_t handle,

View file

@ -15,11 +15,6 @@
* limitations under the License. * limitations under the License.
*/ */
#include <stddef.h>
#include "util/defines.h"
#include "pdu.h"
#include "ctrl.h"
enum llcp { enum llcp {
LLCP_NONE, LLCP_NONE,
LLCP_CONNECTION_UPDATE, LLCP_CONNECTION_UPDATE,
@ -204,7 +199,7 @@ struct connection {
uint8_t rssi_sample_count; uint8_t rssi_sample_count;
#endif /* CONFIG_BLUETOOTH_CONTROLLER_CONN_RSSI */ #endif /* CONFIG_BLUETOOTH_CONTROLLER_CONN_RSSI */
}; };
#define CONNECTION_T_SIZE ALIGN4(sizeof(struct connection)) #define CONNECTION_T_SIZE MROUND(sizeof(struct connection))
struct pdu_data_q_tx { struct pdu_data_q_tx {
uint16_t handle; uint16_t handle;
@ -213,12 +208,12 @@ struct pdu_data_q_tx {
/* Minimum Rx Data allocation size */ /* Minimum Rx Data allocation size */
#define PACKET_RX_DATA_SIZE_MIN \ #define PACKET_RX_DATA_SIZE_MIN \
ALIGN4(offsetof(struct radio_pdu_node_rx, pdu_data) + \ MROUND(offsetof(struct radio_pdu_node_rx, pdu_data) + \
(RADIO_ACPDU_SIZE_MAX + 1)) (RADIO_ACPDU_SIZE_MAX + 1))
/* Minimum Tx Ctrl allocation size */ /* Minimum Tx Ctrl allocation size */
#define PACKET_TX_CTRL_SIZE_MIN \ #define PACKET_TX_CTRL_SIZE_MIN \
ALIGN4(offsetof(struct radio_pdu_node_tx, pdu_data) + \ MROUND(offsetof(struct radio_pdu_node_tx, pdu_data) + \
offsetof(struct pdu_data, payload) + 27) offsetof(struct pdu_data, payload) + 27)
/** @todo fix starvation when ctrl rx in radio ISR /** @todo fix starvation when ctrl rx in radio ISR
@ -232,7 +227,7 @@ struct pdu_data_q_tx {
#define LL_MEM_TXQ (sizeof(struct pdu_data_q_tx) * \ #define LL_MEM_TXQ (sizeof(struct pdu_data_q_tx) * \
(RADIO_PACKET_COUNT_TX_MAX + 2)) (RADIO_PACKET_COUNT_TX_MAX + 2))
#define LL_MEM_RX_POOL_SZ (ALIGN4(offsetof(struct radio_pdu_node_rx,\ #define LL_MEM_RX_POOL_SZ (MROUND(offsetof(struct radio_pdu_node_rx,\
pdu_data) + ((\ pdu_data) + ((\
(RADIO_ACPDU_SIZE_MAX + 1) < \ (RADIO_ACPDU_SIZE_MAX + 1) < \
(offsetof(struct pdu_data, payload) + \ (offsetof(struct pdu_data, payload) + \
@ -247,7 +242,7 @@ struct pdu_data_q_tx {
4) + RADIO_CONNECTION_CONTEXT_MAX)) 4) + RADIO_CONNECTION_CONTEXT_MAX))
#define LL_MEM_TX_CTRL_POOL (PACKET_TX_CTRL_SIZE_MIN * PACKET_MEM_COUNT_TX_CTRL) #define LL_MEM_TX_CTRL_POOL (PACKET_TX_CTRL_SIZE_MIN * PACKET_MEM_COUNT_TX_CTRL)
#define LL_MEM_TX_DATA_POOL ((ALIGN4(offsetof( \ #define LL_MEM_TX_DATA_POOL ((MROUND(offsetof( \
struct radio_pdu_node_tx, pdu_data) + \ struct radio_pdu_node_tx, pdu_data) + \
offsetof(struct pdu_data, payload) + \ offsetof(struct pdu_data, payload) + \
RADIO_PACKET_TX_DATA_SIZE)) \ RADIO_PACKET_TX_DATA_SIZE)) \

View file

@ -17,14 +17,18 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "defines.h"
#include "mem.h" #include <soc.h>
#include "ticker.h"
#include "ccm.h" #include "ccm.h"
#include "radio.h" #include "radio.h"
#include "mem.h"
#include "util.h"
#include "ticker.h"
#include "pdu.h" #include "pdu.h"
#include "ctrl.h" #include "ctrl.h"
#include "ll.h" #include "ll.h"
#include "debug.h" #include "debug.h"

View file

@ -18,7 +18,7 @@
#ifndef _PDU_H_ #ifndef _PDU_H_
#define _PDU_H_ #define _PDU_H_
#include <toolchain.h> #define BDADDR_SIZE 6
struct pdu_adv_payload_adv_ind { struct pdu_adv_payload_adv_ind {
uint8_t addr[BDADDR_SIZE]; uint8_t addr[BDADDR_SIZE];

View file

@ -17,26 +17,29 @@
#include <stdint.h> #include <stdint.h>
#include "hal_rtc.h" #include "cntr.h"
#include "hal_work.h"
#include "work.h"
#include "ticker.h" #include "ticker.h"
#include "config.h"
#include <soc.h>
#include <bluetooth/log.h>
#include "debug.h" #include "debug.h"
/***************************************************************************** /*****************************************************************************
* Defines * Defines
****************************************************************************/ ****************************************************************************/
#define TICKER_DOUBLE_BUFFER_SIZE 2 #define DOUBLE_BUFFER_SIZE 2
#define TICKER_RTC_CC_OFFSET_MIN 3 #define COUNTER_CMP_OFFSET_MIN 3
#define CALL_ID_TRIGGER 0
#define CALL_ID_WORKER 1
#define CALL_ID_JOB 2
#define CALL_ID_USER 3
/***************************************************************************** /*****************************************************************************
* Types * Types
****************************************************************************/ ****************************************************************************/
typedef void (*ticker_fp_sched) (uint8_t chain);
typedef void (*ticker_fp_compare_set) (uint32_t cc);
struct ticker_node { struct ticker_node {
uint8_t next; uint8_t next;
@ -119,16 +122,16 @@ struct ticker_instance {
uint8_t count_user; uint8_t count_user;
uint8_t ticks_elapsed_first; uint8_t ticks_elapsed_first;
uint8_t ticks_elapsed_last; uint8_t ticks_elapsed_last;
uint32_t ticks_elapsed[TICKER_DOUBLE_BUFFER_SIZE]; uint32_t ticks_elapsed[DOUBLE_BUFFER_SIZE];
uint32_t ticks_current; uint32_t ticks_current;
uint8_t ticker_id_head; uint8_t ticker_id_head;
uint8_t ticker_id_slot_previous; uint8_t ticker_id_slot_previous;
uint16_t ticks_slot_previous; uint16_t ticks_slot_previous;
uint8_t job_guard; uint8_t job_guard;
uint8_t worker_trigger; uint8_t worker_trigger;
ticker_fp_sched fp_worker_sched; uint8_t (*fp_caller_id_get)(uint8_t user_id);
ticker_fp_sched fp_job_sched; void (*fp_sched)(uint8_t caller_id, uint8_t callee_id, uint8_t chain);
ticker_fp_compare_set fp_compare_set; void (*fp_cmp_set)(uint32_t value);
}; };
/***************************************************************************** /*****************************************************************************
@ -356,8 +359,8 @@ static inline void ticker_worker(struct ticker_instance *instance)
} }
/* ticks_elapsed is collected here, job will use it */ /* ticks_elapsed is collected here, job will use it */
ticks_elapsed = ticks_elapsed = ticker_ticks_diff_get(cntr_cnt_get(),
ticker_ticks_diff_get(rtc_tick_get(), instance->ticks_current); instance->ticks_current);
/* initialise actual elapsed ticks being consumed */ /* initialise actual elapsed ticks being consumed */
ticks_expired = 0; ticks_expired = 0;
@ -413,7 +416,7 @@ static inline void ticker_worker(struct ticker_instance *instance)
uint8_t last; uint8_t last;
last = instance->ticks_elapsed_last + 1; last = instance->ticks_elapsed_last + 1;
if (last == TICKER_DOUBLE_BUFFER_SIZE) { if (last == DOUBLE_BUFFER_SIZE) {
last = 0; last = 0;
} }
instance->ticks_elapsed_last = last; instance->ticks_elapsed_last = last;
@ -423,7 +426,7 @@ static inline void ticker_worker(struct ticker_instance *instance)
instance->worker_trigger = 0; instance->worker_trigger = 0;
instance->fp_job_sched(1); instance->fp_sched(CALL_ID_WORKER, CALL_ID_JOB, 1);
} }
static void prepare_ticks_to_expire(struct ticker_node *ticker, static void prepare_ticks_to_expire(struct ticker_node *ticker,
@ -498,7 +501,7 @@ static inline void ticker_job_node_update(struct ticker_node *ticker,
uint32_t ticks_now; uint32_t ticks_now;
uint32_t ticks_to_expire = ticker->ticks_to_expire; uint32_t ticks_to_expire = ticker->ticks_to_expire;
ticks_now = rtc_tick_get(); ticks_now = cntr_cnt_get();
ticks_elapsed += ticker_ticks_diff_get(ticks_now, ticks_current); ticks_elapsed += ticker_ticks_diff_get(ticks_now, ticks_current);
if (ticks_to_expire > ticks_elapsed) { if (ticks_to_expire > ticks_elapsed) {
ticks_to_expire -= ticks_elapsed; ticks_to_expire -= ticks_elapsed;
@ -685,7 +688,8 @@ static inline uint8_t ticker_job_list_manage(
*/ */
/* sched job to run after worker bottom half. /* sched job to run after worker bottom half.
*/ */
instance->fp_job_sched(1); instance->fp_sched(CALL_ID_JOB,
CALL_ID_JOB, 1);
/* Update the index upto which management is /* Update the index upto which management is
* complete. * complete.
@ -1023,7 +1027,7 @@ static inline void ticker_job_compare_update(
uint32_t i; uint32_t i;
if (instance->ticker_id_head == TICKER_NULL) { if (instance->ticker_id_head == TICKER_NULL) {
if (rtc_stop() == 0) { if (cntr_stop() == 0) {
instance->ticks_slot_previous = 0; instance->ticks_slot_previous = 0;
} }
@ -1033,9 +1037,9 @@ static inline void ticker_job_compare_update(
if (ticker_id_old_head == TICKER_NULL) { if (ticker_id_old_head == TICKER_NULL) {
uint32_t ticks_current; uint32_t ticks_current;
ticks_current = rtc_tick_get(); ticks_current = cntr_cnt_get();
if (rtc_start() == 0) { if (cntr_start() == 0) {
instance->ticks_current = ticks_current; instance->ticks_current = ticks_current;
} }
} }
@ -1056,19 +1060,19 @@ static inline void ticker_job_compare_update(
LL_ASSERT(i); LL_ASSERT(i);
i--; i--;
ctr = rtc_tick_get(); ctr = cntr_cnt_get();
cc = instance->ticks_current; cc = instance->ticks_current;
ticks_elapsed = ticker_ticks_diff_get(ctr, cc) + ticks_elapsed = ticker_ticks_diff_get(ctr, cc) +
TICKER_RTC_CC_OFFSET_MIN; COUNTER_CMP_OFFSET_MIN;
cc += ((ticks_elapsed < ticks_to_expire) ? cc += ((ticks_elapsed < ticks_to_expire) ?
ticks_to_expire : ticks_elapsed); ticks_to_expire : ticks_elapsed);
cc &= 0x00FFFFFF; cc &= 0x00FFFFFF;
instance->fp_compare_set(cc); instance->fp_cmp_set(cc);
ctr_post = rtc_tick_get(); ctr_post = cntr_cnt_get();
} while ((ticker_ticks_diff_get(ctr_post, ctr) + } while ((ticker_ticks_diff_get(ctr_post, ctr) +
TICKER_RTC_CC_OFFSET_MIN) > ticker_ticks_diff_get(cc, ctr)); COUNTER_CMP_OFFSET_MIN) > ticker_ticks_diff_get(cc, ctr));
} }
static inline void ticker_job(struct ticker_instance *instance) static inline void ticker_job(struct ticker_instance *instance)
@ -1099,7 +1103,7 @@ static inline void ticker_job(struct ticker_instance *instance)
uint8_t first; uint8_t first;
first = instance->ticks_elapsed_first + 1; first = instance->ticks_elapsed_first + 1;
if (first == TICKER_DOUBLE_BUFFER_SIZE) { if (first == DOUBLE_BUFFER_SIZE) {
first = 0; first = 0;
} }
instance->ticks_elapsed_first = first; instance->ticks_elapsed_first = first;
@ -1172,79 +1176,341 @@ static inline void ticker_job(struct ticker_instance *instance)
/* trigger worker if deferred */ /* trigger worker if deferred */
if (instance->worker_trigger) { if (instance->worker_trigger) {
instance->fp_worker_sched(1); instance->fp_sched(CALL_ID_JOB, CALL_ID_WORKER, 1);
} }
DEBUG_TICKER_JOB(0); DEBUG_TICKER_JOB(0);
} }
/***************************************************************************** /*****************************************************************************
* Instances Work Helpers * Instances Helpers
*
* TODO: decouple it from using work/mayfly in this file and dynamically
* import it.
****************************************************************************/ ****************************************************************************/
static void ticker_instance0_worker_sched(uint8_t chain) #include "mayfly.h"
{ #include "config.h"
static struct work instance0_worker_irq = {
0, 0, 0, WORK_TICKER_WORKER0_IRQ, (work_fp) ticker_worker,
&_instance[0]
};
static uint8_t ticker_instance0_caller_id_get(uint8_t user_id)
{
if (user_id == TICKER_MAYFLY_CALL_ID_PROGRAM) {
return CALL_ID_USER;
} else if (user_id == TICKER_MAYFLY_CALL_ID_JOB0) {
return CALL_ID_JOB;
} else if (user_id == TICKER_MAYFLY_CALL_ID_WORKER0) {
return CALL_ID_WORKER;
} else if (user_id == TICKER_MAYFLY_CALL_ID_TRIGGER) {
return CALL_ID_TRIGGER;
}
LL_ASSERT(0);
return 0;
}
static uint8_t ticker_instance1_caller_id_get(uint8_t user_id)
{
if (user_id == TICKER_MAYFLY_CALL_ID_PROGRAM) {
return CALL_ID_USER;
} else if (user_id == TICKER_MAYFLY_CALL_ID_JOB1) {
return CALL_ID_JOB;
} else if (user_id == TICKER_MAYFLY_CALL_ID_WORKER1) {
return CALL_ID_WORKER;
} else if (user_id == TICKER_MAYFLY_CALL_ID_TRIGGER) {
return CALL_ID_TRIGGER;
}
LL_ASSERT(0);
return 0;
}
static void ticker_instance0_sched(uint8_t caller_id, uint8_t callee_id,
uint8_t chain)
{
/* return value not checked as we allow multiple calls to schedule /* return value not checked as we allow multiple calls to schedule
* before being actually needing the work to complete before new * before being actually needing the work to complete before new
* schedule. * schedule.
*/ */
work_schedule(&instance0_worker_irq, chain); switch (caller_id) {
case CALL_ID_TRIGGER:
switch (callee_id) {
case CALL_ID_WORKER:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
&_instance[0],
(void *)ticker_worker
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_TRIGGER,
TICKER_MAYFLY_CALL_ID_WORKER0,
chain,
&m);
}
break;
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[0],
(void *)ticker_job
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_TRIGGER,
TICKER_MAYFLY_CALL_ID_JOB0,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
case CALL_ID_WORKER:
switch (callee_id) {
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[0],
(void *)ticker_job
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_WORKER0,
TICKER_MAYFLY_CALL_ID_JOB0,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
case CALL_ID_JOB:
switch (callee_id) {
case CALL_ID_WORKER:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[0],
(void *)ticker_worker
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_JOB0,
TICKER_MAYFLY_CALL_ID_WORKER0,
chain,
&m);
}
break;
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[0],
(void *)ticker_job
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_JOB0,
TICKER_MAYFLY_CALL_ID_JOB0,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
default:
switch (callee_id) {
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[0],
(void *)ticker_job
};
/* TODO: scheduler lock, if OS used */
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_PROGRAM,
TICKER_MAYFLY_CALL_ID_JOB0,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
}
} }
static void ticker_instance0_job_sched(uint8_t chain) static void ticker_instance1_sched(uint8_t caller_id, uint8_t callee_id,
uint8_t chain)
{ {
static struct work instance0_job_irq = {
0, 0, 0, WORK_TICKER_JOB0_IRQ, (work_fp) ticker_job,
&_instance[0]
};
/* return value not checked as we allow multiple calls to schedule /* return value not checked as we allow multiple calls to schedule
* before being actually needing the work to complete before new * before being actually needing the work to complete before new
* schedule. * schedule.
*/ */
work_schedule(&instance0_job_irq, chain); switch (caller_id) {
case CALL_ID_TRIGGER:
switch (callee_id) {
case CALL_ID_WORKER:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
&_instance[1],
(void *)ticker_worker
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_TRIGGER,
TICKER_MAYFLY_CALL_ID_WORKER1,
chain,
&m);
}
break;
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[1],
(void *)ticker_job
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_TRIGGER,
TICKER_MAYFLY_CALL_ID_JOB1,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
case CALL_ID_WORKER:
switch (callee_id) {
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[1],
(void *)ticker_job
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_WORKER1,
TICKER_MAYFLY_CALL_ID_JOB1,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
case CALL_ID_JOB:
switch (callee_id) {
case CALL_ID_WORKER:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[1],
(void *)ticker_worker
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_JOB1,
TICKER_MAYFLY_CALL_ID_WORKER1,
chain,
&m);
}
break;
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[1],
(void *)ticker_job
};
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_JOB1,
TICKER_MAYFLY_CALL_ID_JOB1,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
default:
switch (callee_id) {
case CALL_ID_JOB:
{
static void *link[2];
static struct mayfly m = {
0, 0, link,
(void *)&_instance[1],
(void *)ticker_job
};
/* TODO: scheduler lock, if OS used */
mayfly_enqueue(TICKER_MAYFLY_CALL_ID_PROGRAM,
TICKER_MAYFLY_CALL_ID_JOB1,
chain,
&m);
}
break;
default:
LL_ASSERT(0);
break;
}
break;
}
} }
static void ticker_instance0_rtc_compare_set(uint32_t value) static void ticker_instance0_cmp_set(uint32_t value)
{ {
rtc_compare_set(0, value); cntr_cmp_set(0, value);
} }
static void ticker_instance1_worker_sched(uint8_t chain) static void ticker_instance1_cmp_set(uint32_t value)
{ {
static struct work instance1_worker_irq = { cntr_cmp_set(1, value);
0, 0, 0, WORK_TICKER_WORKER1_IRQ, (work_fp) ticker_worker,
&_instance[1]
};
/* return value not checked as we allow multiple calls to schedule
* before being actually needing the work to complete before new
* schedule.
*/
work_schedule(&instance1_worker_irq, chain);
}
static void ticker_instance1_job_sched(uint8_t chain)
{
static struct work instance1_job_irq = {
0, 0, 0, WORK_TICKER_JOB1_IRQ, (work_fp) ticker_job,
&_instance[1]
};
/* return value not checked as we allow multiple calls to schedule
* before being actually needing the work to complete before new
* schedule.
*/
work_schedule(&instance1_job_irq, chain);
}
static void ticker_instance1_rtc_compare_set(uint32_t value)
{
rtc_compare_set(1, value);
} }
/***************************************************************************** /*****************************************************************************
@ -1268,21 +1534,15 @@ uint32_t ticker_init(uint8_t instance_index, uint8_t count_node, void *node,
switch (instance_index) { switch (instance_index) {
case 0: case 0:
instance->fp_worker_sched = instance->fp_caller_id_get = ticker_instance0_caller_id_get;
ticker_instance0_worker_sched; instance->fp_sched = ticker_instance0_sched;
instance->fp_job_sched = instance->fp_cmp_set = ticker_instance0_cmp_set;
ticker_instance0_job_sched;
instance->fp_compare_set =
ticker_instance0_rtc_compare_set;
break; break;
case 1: case 1:
instance->fp_worker_sched = instance->fp_caller_id_get = ticker_instance1_caller_id_get;
ticker_instance1_worker_sched; instance->fp_sched = ticker_instance1_sched;
instance->fp_job_sched = instance->fp_cmp_set = ticker_instance1_cmp_set;
ticker_instance1_job_sched;
instance->fp_compare_set =
ticker_instance1_rtc_compare_set;
break; break;
default: default:
@ -1320,9 +1580,14 @@ uint32_t ticker_init(uint8_t instance_index, uint8_t count_node, void *node,
void ticker_trigger(uint8_t instance_index) void ticker_trigger(uint8_t instance_index)
{ {
if (_instance[instance_index].fp_worker_sched) { DEBUG_TICKER_ISR(1);
_instance[instance_index].fp_worker_sched(1);
if (_instance[instance_index].fp_sched) {
_instance[instance_index].fp_sched(CALL_ID_TRIGGER,
CALL_ID_WORKER, 1);
} }
DEBUG_TICKER_ISR(0);
} }
uint32_t ticker_start(uint8_t instance_index, uint8_t user_id, uint32_t ticker_start(uint8_t instance_index, uint8_t user_id,
@ -1341,7 +1606,7 @@ uint32_t ticker_start(uint8_t instance_index, uint8_t user_id,
user = &instance->user[user_id]; user = &instance->user[user_id];
last = user->last + 1; last = user->last + 1;
if (last == user->count_user_op) { if (last >= user->count_user_op) {
last = 0; last = 0;
} }
@ -1366,7 +1631,7 @@ uint32_t ticker_start(uint8_t instance_index, uint8_t user_id,
user->last = last; user->last = last;
instance->fp_job_sched(0); instance->fp_sched(instance->fp_caller_id_get(user_id), CALL_ID_JOB, 0);
return user_op->status; return user_op->status;
} }
@ -1385,7 +1650,7 @@ uint32_t ticker_update(uint8_t instance_index, uint8_t user_id,
user = &instance->user[user_id]; user = &instance->user[user_id];
last = user->last + 1; last = user->last + 1;
if (last == user->count_user_op) { if (last >= user->count_user_op) {
last = 0; last = 0;
} }
@ -1408,7 +1673,7 @@ uint32_t ticker_update(uint8_t instance_index, uint8_t user_id,
user->last = last; user->last = last;
instance->fp_job_sched(0); instance->fp_sched(instance->fp_caller_id_get(user_id), CALL_ID_JOB, 0);
return user_op->status; return user_op->status;
} }
@ -1425,7 +1690,7 @@ uint32_t ticker_stop(uint8_t instance_index, uint8_t user_id,
user = &instance->user[user_id]; user = &instance->user[user_id];
last = user->last + 1; last = user->last + 1;
if (last == user->count_user_op) { if (last >= user->count_user_op) {
last = 0; last = 0;
} }
@ -1442,7 +1707,7 @@ uint32_t ticker_stop(uint8_t instance_index, uint8_t user_id,
user->last = last; user->last = last;
instance->fp_job_sched(0); instance->fp_sched(instance->fp_caller_id_get(user_id), CALL_ID_JOB, 0);
return user_op->status; return user_op->status;
} }
@ -1461,7 +1726,7 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id,
user = &instance->user[user_id]; user = &instance->user[user_id];
last = user->last + 1; last = user->last + 1;
if (last == user->count_user_op) { if (last >= user->count_user_op) {
last = 0; last = 0;
} }
@ -1481,7 +1746,7 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id,
user->last = last; user->last = last;
instance->fp_job_sched(0); instance->fp_sched(instance->fp_caller_id_get(user_id), CALL_ID_JOB, 0);
return user_op->status; return user_op->status;
} }
@ -1497,7 +1762,7 @@ uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
user = &instance->user[user_id]; user = &instance->user[user_id];
last = user->last + 1; last = user->last + 1;
if (last == user->count_user_op) { if (last >= user->count_user_op) {
last = 0; last = 0;
} }
@ -1514,21 +1779,21 @@ uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
user->last = last; user->last = last;
instance->fp_job_sched(0); instance->fp_sched(instance->fp_caller_id_get(user_id), CALL_ID_JOB, 0);
return user_op->status; return user_op->status;
} }
void ticker_job_sched(uint8_t instance_index) void ticker_job_sched(uint8_t instance_index, uint8_t user_id)
{ {
struct ticker_instance *instance = &_instance[instance_index]; struct ticker_instance *instance = &_instance[instance_index];
instance->fp_job_sched(0); instance->fp_sched(instance->fp_caller_id_get(user_id), CALL_ID_JOB, 0);
} }
uint32_t ticker_ticks_now_get(void) uint32_t ticker_ticks_now_get(void)
{ {
return rtc_tick_get(); return cntr_cnt_get();
} }
uint32_t ticker_ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old) uint32_t ticker_ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old)

View file

@ -131,7 +131,7 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id,
ticker_op_func fp_op_func, void *op_context); ticker_op_func fp_op_func, void *op_context);
uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id, uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
ticker_op_func fp_op_func, void *op_context); ticker_op_func fp_op_func, void *op_context);
void ticker_job_sched(uint8_t instance_index); void ticker_job_sched(uint8_t instance_index, uint8_t user_id);
uint32_t ticker_ticks_now_get(void); uint32_t ticker_ticks_now_get(void);
uint32_t ticker_ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old); uint32_t ticker_ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old);

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define MAYFLY_CALL_ID_0 0
#define MAYFLY_CALL_ID_1 1
#define MAYFLY_CALL_ID_2 2
#define MAYFLY_CALL_ID_PROGRAM 3
#define MAYFLY_CALLER_COUNT 4
#define MAYFLY_CALLEE_COUNT 4
#define TICKER_MAYFLY_CALL_ID_TRIGGER MAYFLY_CALL_ID_0
#define TICKER_MAYFLY_CALL_ID_WORKER0 MAYFLY_CALL_ID_0
#define TICKER_MAYFLY_CALL_ID_WORKER1 MAYFLY_CALL_ID_2
#define TICKER_MAYFLY_CALL_ID_JOB0 MAYFLY_CALL_ID_1
#define TICKER_MAYFLY_CALL_ID_JOB1 MAYFLY_CALL_ID_2
#define TICKER_MAYFLY_CALL_ID_PROGRAM MAYFLY_CALL_ID_PROGRAM
#define TICKER_MAYFLY_CALL_ID_WORKER0_PRIO 0
#define TICKER_MAYFLY_CALL_ID_WORKER1_PRIO 1
#define TICKER_MAYFLY_CALL_ID_JOB0_PRIO 0
#define TICKER_MAYFLY_CALL_ID_JOB1_PRIO 1
#endif /* _CONFIG_H_ */

View file

@ -1,34 +0,0 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEFINES_H_
#define _DEFINES_H_
#include <toolchain.h>
#if !defined(ALIGNED)
#define ALIGNED(x) __aligned(x)
#endif
#define ALIGN4(x) (((uint32_t)(x)+3) & (~((uint32_t)3)))
#define DOUBLE_BUFFER_SIZE 2
#define TRIPLE_BUFFER_SIZE 3
#define BDADDR_SIZE 6
#endif /* _DEFINES_H_ */

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include "memq.h"
#include "mayfly.h"
#include "config.h"
static struct {
void *head;
void *tail;
} mft[MAYFLY_CALLEE_COUNT][MAYFLY_CALLER_COUNT];
static void *mfl[MAYFLY_CALLEE_COUNT][MAYFLY_CALLER_COUNT][2];
void mayfly_init(void)
{
uint8_t callee_id;
callee_id = MAYFLY_CALLEE_COUNT;
while (callee_id--) {
uint8_t caller_id;
caller_id = MAYFLY_CALLER_COUNT;
while (caller_id--) {
memq_init(mfl[callee_id][caller_id],
&mft[callee_id][caller_id].head,
&mft[callee_id][caller_id].tail);
}
}
}
uint32_t mayfly_enqueue(uint8_t caller_id, uint8_t callee_id, uint8_t chain,
struct mayfly *m)
{
uint8_t state;
uint8_t ack;
chain = chain || !mayfly_prio_is_equal(caller_id, callee_id) ||
!mayfly_is_enabled(caller_id, callee_id);
/* shadow the ack */
ack = m->_ack;
/* already in queue */
state = (m->_req - ack) & 0x03;
if (state != 0) {
if (chain) {
if (state != 1) {
/* mark as ready in queue */
m->_req = ack + 1;
/* pend the callee for execution */
mayfly_pend(caller_id, callee_id);
return 0;
}
/* already ready */
return 1;
}
/* mark as done in queue, and fall thru */
m->_req = ack + 2;
}
/* handle mayfly(s) that can be inline */
if (!chain) {
/* call fp */
m->fp(m->param);
return 0;
}
/* new, add as ready in the queue */
m->_req = ack + 1;
memq_enqueue(m, m->_link, &mft[callee_id][caller_id].tail);
/* pend the callee for execution */
mayfly_pend(caller_id, callee_id);
return 0;
}
void mayfly_run(uint8_t callee_id)
{
uint8_t caller_id;
/* iterate through each caller queue to this callee_id */
caller_id = MAYFLY_CALLER_COUNT;
while (caller_id--) {
void *link;
struct mayfly *m = 0;
/* fetch mayfly in callee queue, if any */
link = memq_peek(mft[callee_id][caller_id].tail,
mft[callee_id][caller_id].head,
(void **)&m);
while (link) {
uint8_t state;
uint8_t req;
/* execute work if ready */
req = m->_req;
state = (req - m->_ack) & 0x03;
if (state == 1) {
/* mark mayfly as ran */
m->_ack--;
/* call the mayfly function */
m->fp(m->param);
}
/* dequeue if not re-pended */
req = m->_req;
if (((req - m->_ack) & 0x03) != 1) {
memq_dequeue(mft[callee_id][caller_id].tail,
&mft[callee_id][caller_id].head,
0);
/* release link into dequeued mayfly struct */
m->_link = link;
/* reset mayfly state to idle */
m->_ack = req;
}
/* fetch next mayfly in callee queue, if any */
link = memq_peek(mft[callee_id][caller_id].tail,
mft[callee_id][caller_id].head,
(void **)&m);
/* yield out of mayfly_run if a mayfly function was
* called.
*/
if (state == 1) {
/* pend callee (tailchain) if mayfly queue is
* not empty.
*/
if (link) {
mayfly_pend(callee_id, callee_id);
}
return;
}
}
}
}

View file

@ -15,24 +15,25 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef _WORK_H_ #ifndef _MAYFLY_H_
#define _WORK_H_ #define _MAYFLY_H_
typedef void (*work_fp) (void *params); struct mayfly {
uint8_t volatile _req;
struct work { uint8_t _ack;
void *next; void *_link;
uint8_t req; void *param;
uint8_t ack; void (*fp)(void *);
uint8_t group;
work_fp fp;
void *params;
}; };
void work_enable(uint8_t group); void mayfly_init(void);
void work_disable(uint8_t group); uint32_t mayfly_enqueue(uint8_t caller_id, uint8_t callee_id, uint8_t chain,
uint32_t work_is_enabled(uint8_t group); struct mayfly *m);
uint32_t work_schedule(struct work *w, uint8_t chain); void mayfly_run(uint8_t callee_id);
void work_run(uint8_t group);
#endif /* _WORK_H_ */ extern void mayfly_enable(uint8_t caller_id, uint8_t callee_id, uint8_t enable);
extern uint32_t mayfly_is_enabled(uint8_t caller_id, uint8_t callee_id);
extern uint32_t mayfly_prio_is_equal(uint8_t caller_id, uint8_t callee_id);
extern void mayfly_pend(uint8_t caller_id, uint8_t callee_id);
#endif /* _MAYFLY_H_ */

View file

@ -18,7 +18,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "defines.h" #include "util.h"
#include "mem.h" #include "mem.h"
@ -27,15 +27,17 @@ void mem_init(void *mem_pool, uint16_t mem_size, uint16_t mem_count,
{ {
*mem_head = mem_pool; *mem_head = mem_pool;
/* Store free mem_count after the list's next pointer */ /* Store free mem_count after the list's next pointer at an aligned
memcpy(((uint8_t *)mem_pool + sizeof(mem_pool)), * memory location to ensure atomic read/write (in ARM for now).
(uint8_t *)&mem_count, sizeof(mem_count)); */
*((uint16_t *)MROUND((uint8_t *)mem_pool + sizeof(mem_pool))) =
mem_count;
/* Initialize next pointers to form a free list, /* Initialize next pointers to form a free list,
* next pointer is stored in the first 32-bit of each block * next pointer is stored in the first 32-bit of each block
*/ */
memset(((uint8_t *)mem_pool + (mem_size * (--mem_count))), 0, memset(((uint8_t *)mem_pool + (mem_size * (--mem_count))), 0,
sizeof(mem_pool)); sizeof(mem_pool));
while (mem_count--) { while (mem_count--) {
uint32_t next; uint32_t next;
@ -50,23 +52,24 @@ void *mem_acquire(void **mem_head)
{ {
if (*mem_head) { if (*mem_head) {
uint16_t free_count; uint16_t free_count;
void *head;
void *mem; void *mem;
/* Get the free count from the list and decrement it */ /* Get the free count from the list and decrement it */
memcpy((void *)&free_count, free_count = *((uint16_t *)MROUND((uint8_t *)*mem_head +
((uint8_t *)*mem_head + sizeof(mem_head)), sizeof(mem_head)));
sizeof(free_count));
free_count--; free_count--;
mem = *mem_head; mem = *mem_head;
memcpy(mem_head, mem, sizeof(*mem_head)); memcpy(&head, mem, sizeof(head));
/* Store free mem_count after the list's next pointer */ /* Store free mem_count after the list's next pointer */
if (*mem_head) { if (head) {
memcpy(((uint8_t *)*mem_head + sizeof(mem_head)), *((uint16_t *)MROUND((uint8_t *)head + sizeof(head))) =
(uint8_t *)&free_count, sizeof(free_count)); free_count;
} }
*mem_head = head;
return mem; return mem;
} }
@ -79,17 +82,17 @@ void mem_release(void *mem, void **mem_head)
/* Get the free count from the list and increment it */ /* Get the free count from the list and increment it */
if (*mem_head) { if (*mem_head) {
memcpy(&free_count, ((uint8_t *)*mem_head + sizeof(mem_head)), free_count = *((uint16_t *)MROUND((uint8_t *)*mem_head +
sizeof(free_count)); sizeof(mem_head)));
} }
free_count++; free_count++;
memcpy(mem, mem_head, sizeof(mem)); memcpy(mem, mem_head, sizeof(mem));
*mem_head = mem;
/* Store free mem_count after the list's next pointer */ /* Store free mem_count after the list's next pointer */
memcpy(((uint8_t *)*mem_head + sizeof(mem_head)), *((uint16_t *)MROUND((uint8_t *)mem + sizeof(mem))) = free_count;
(uint8_t *)&free_count, sizeof(free_count));
*mem_head = mem;
} }
uint16_t mem_free_count_get(void *mem_head) uint16_t mem_free_count_get(void *mem_head)
@ -98,8 +101,8 @@ uint16_t mem_free_count_get(void *mem_head)
/* Get the free count from the list */ /* Get the free count from the list */
if (mem_head) { if (mem_head) {
memcpy(&free_count, ((uint8_t *)mem_head + sizeof(mem_head)), free_count = *((uint16_t *)MROUND((uint8_t *)mem_head +
sizeof(free_count)); sizeof(mem_head)));
} }
return free_count; return free_count;
@ -137,9 +140,9 @@ uint8_t mem_is_zero(uint8_t *src, uint16_t len)
uint32_t mem_ut(void) uint32_t mem_ut(void)
{ {
#define BLOCK_SIZE ALIGN4(10) #define BLOCK_SIZE MROUND(10)
#define BLOCK_COUNT 10 #define BLOCK_COUNT 10
uint8_t ALIGNED(4) pool[BLOCK_COUNT][BLOCK_SIZE]; uint8_t MALIGN(4) pool[BLOCK_COUNT][BLOCK_SIZE];
void *mem_free; void *mem_free;
void *mem_used; void *mem_used;
uint16_t mem_free_count; uint16_t mem_free_count;

View file

@ -18,6 +18,14 @@
#ifndef _MEM_H_ #ifndef _MEM_H_
#define _MEM_H_ #define _MEM_H_
#ifndef MALIGN
#define MALIGN(x) __attribute__((aligned(x)))
#endif
#ifndef MROUND
#define MROUND(x) (((uint32_t)(x)+3) & (~((uint32_t)3)))
#endif
void mem_init(void *mem_pool, uint16_t mem_size, uint16_t mem_count, void mem_init(void *mem_pool, uint16_t mem_size, uint16_t mem_count,
void **mem_head); void **mem_head);
void *mem_acquire(void **mem_head); void *mem_acquire(void **mem_head);

View file

@ -18,6 +18,14 @@
#ifndef _UTIL_H_ #ifndef _UTIL_H_
#define _UTIL_H_ #define _UTIL_H_
#ifndef DOUBLE_BUFFER_SIZE
#define DOUBLE_BUFFER_SIZE 2
#endif
#ifndef TRIPLE_BUFFER_SIZE
#define TRIPLE_BUFFER_SIZE 3
#endif
uint8_t util_ones_count_get(uint8_t *octets, uint8_t octets_len); uint8_t util_ones_count_get(uint8_t *octets, uint8_t octets_len);
#endif #endif

View file

@ -1,165 +0,0 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <irq.h>
#include "work.h"
static struct work *_work_head;
static int _irq_is_priority_equal(unsigned int irq)
{
unsigned int curr_ctx;
int curr_prio;
curr_ctx = _ScbActiveVectorGet();
if (curr_ctx > 15) {
/* Interrupts */
curr_prio = _NvicIrqPrioGet(curr_ctx - 16);
} else if (curr_ctx > 3) {
/* Execeptions */
curr_prio = _ScbExcPrioGet(curr_ctx);
} else if (curr_ctx > 0) {
/* Fixed Priority Exceptions: -3, -2, -1 priority */
curr_prio = curr_ctx - 4;
} else {
/* Thread mode */
curr_prio = 256;
}
return (_NvicIrqPrioGet(irq) == curr_prio);
}
void work_enable(uint8_t group)
{
irq_enable(group);
}
void work_disable(uint8_t group)
{
irq_disable(group);
}
uint32_t work_is_enabled(uint8_t group)
{
return irq_is_enabled(group);
}
uint32_t work_schedule(struct work *w, uint8_t chain)
{
uint32_t imask = irq_lock();
struct work *prev;
struct work *curr;
/* Dequeue expired work at head */
while ((_work_head)
&& (_work_head->ack == _work_head->req)
) {
_work_head = _work_head->next;
}
/* Dequeue expired in between list and find last node */
curr = _work_head;
prev = curr;
while (curr) {
/* delete expired work */
if (curr->ack == curr->req) {
prev->next = curr->next;
} else {
prev = curr;
}
curr = curr->next;
}
/* chain, if explicitly requested, or if work not at current level */
chain = chain || (!_irq_is_priority_equal(w->group))
|| (!irq_is_enabled(w->group));
/* Already in List */
curr = _work_head;
while (curr) {
if (curr == w) {
if (!chain) {
break;
}
irq_unlock(imask);
return 1;
}
curr = curr->next;
}
/* handle work(s) that can be inline */
if (!chain) {
w->req = w->ack;
irq_unlock(imask);
if (w->fp) {
w->fp(w->params);
}
return 0;
}
/* New, add to the list */
w->req = w->ack + 1;
w->next = 0;
if (prev == curr) {
_work_head = w;
} else {
prev->next = w;
}
_NvicIrqPend(w->group);
irq_unlock(imask);
return 0;
}
void work_run(uint8_t group)
{
uint32_t imask = irq_lock();
struct work *curr = _work_head;
while (curr) {
if ((curr->group == group) && (curr->ack != curr->req)) {
curr->ack = curr->req;
if (curr->fp) {
if (curr->next) {
_NvicIrqPend(group);
}
irq_unlock(imask);
curr->fp(curr->params);
return;
}
}
curr = curr->next;
}
irq_unlock(imask);
}