<commit_before>/*
 * Copyright (C) 2018 <NAME>
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 *
 * PLEASE NOTE: This file is only used in SDK version
 */

/*
 * Internally, the SDK uses its own priority-based multitasking system,
 * the *ETS*, to handle hardware components such as the WiFi interface, or to
 * implement event-driven functions such as software timers. ETS periodically
 * executes all ETS tasks with pending events in an infinite loop with the ROM
 * function *ets_run*.
 *
 * ETS doesn't process interrupts directly in interrupt service routines.
 * Instead, they use the *ets_post* ROM function to send an event to one of the
 * ETS tasks, which then processes the interrupts asynchronously. Context
 * switches are not possible in interrupt service routines.
 *
 * To use SDK functions and keep the system alive, ETS tasks with pending
 * events have to be handled. For that purpose
 *
 * - the *ets_task_func* RIOT thread with highest possible priority is used
 * - the ROM functions *ets_run* and *ets_post* are overwritten.
 *
 * The *ets_task_func* RIOT thread is waiting for a thread flag, which is set
 * by the *ets_post function* at the end of an ETS interrupt service routine.
 * The flag indicates that there are ETS tasks with pending events that need
 * to be executed. The *ets_task_func* RIOT thread then calls the *ets_run*
 * function, which performs all ETS tasks with pending events exactly once.
 *
 * Thus, when a hardware component used by the SDK triggers an interrupt, e.g.
 * the WiFi interface, the interrupt sevice routine posts an event to the ETS
 * task by calling the *ets_post* function. The overwritten version of this
 * function sets the thread flag of the *ets_task_func* thread. The thread
 * then calls function *ets_run* to process pending events.
 */

#ifdef MODULE_ESP_SDK

#define ENABLE_DEBUG 0
#include <stdio.h>

#include "irq_arch.h"
#include "mutex.h"
#include "thread.h"

#include "esp/common_macros.h"
#include "sdk/ets_task.h"
#include "sdk/sdk.h"

static uint8_t min_prio = 0;

/* helper function for *ets_run* */
uint8_t ets_highest_1_bit (uint32_t mask)
{
    __asm__ volatile ("nsau %0, %1;" :"=r"(mask) : "r"(mask));
    return 32 - mask;
}

/*
 * Perform the execution of all pending ETS tasks. This is necessary to
 * keep the underlying ETS system used by the SDK alive. It is called from
 * the RIOT thread *ets_task_func*.
 */
void IRAM ets_tasks_run (void)
{
    #if ENABLE_DEBUG
    uint32_t _entry = phy_get_mactime();
    uint32_t _exit;
    ets_printf("ets_tasks_run @%lu\n", _entry);
    #endif

    /* reset hardware watchdog here */
    system_soft_wdt_feed();

    while (1) {
        uint8_t  hbit;
        int state = irq_disable();
        hbit = ets_highest_1_bit (ets_task_exec_mask);
        if (min_prio < hbit) {
            ets_task_tcb_t* task  = &ets_task_tab[hbit-1];
            ETSEvent *      event = &task->queue[task->qposr++];
            if (task->qposr == task->qlength) {
                task->qposr = 0;
            }
            if (--task->qpending == 0) {
                ets_task_exec_mask &= ~task->maskbit;
            }
            ets_task_min_prio = hbit;
            irq_restore(state);
            task->task(event);
            ets_task_min_prio = min_prio;
        }
        else {
            irq_restore(state);
            break;
        }
    }

    #if ENABLE_DEBUG
    _exit = phy_get_mactime();
    ets_printf("ets_tasks_run @%lu for %lu us\n", _entry, _exit - _entry);
    #endif

    /* reset hardware watchdog here again */
    system_soft_wdt_feed();
}


#define THREAD_FLAG_ETS_THREAD (1 << 0)
static volatile thread_t* ets_thread = NULL;

/*
 * Thread *ets_task_func* is waiting for the thread flag THREAD_FLAG_ETS_THREAD
 * indicating that ETS tasks have pending events and need to be executed. When
 * the thread flag is set, it calls the *ets_run* function, which performs
 * all ETS tasks with pending events exactly once. The thread flag is set by
 * the *ets_post* function, which is called at the end of an ETS interrupt
 * service routine.
 */
void *ets_task_func(void *arg)
{
    (void) arg;

    ets_thread = sched_active_thread;
    while (1) {
        thread_flags_wait_one(THREAD_FLAG_ETS_THREAD);
        ets_tasks_run();
    }

    return NULL;
}

/* helper macro for *ets_post */
#define irom_cache_enabled() (*((uint32_t*)0x60000208) & (1 << 17))

/* ETS timer task priority */
#define TIMER_TASK_PRIORITY 31

/* reference to the *ets_post* ROM function */
typedef uint32_t (*ets_post_function_t)(uint32_t prio, ETSSignal sig, ETSParam par);
static ets_post_function_t ets_post_rom = (ets_post_function_t)0x40000e24;

/*
 * Overwritten version of ROM function *ets_post*.
 *
 * ETS doesn't process interrupts directly in interrupt service routines.
 * Instead, they use the *ets_post* ROM function to send an event to one of the
 * ETS tasks, which then processes the interrupts asynchronously. Context
 * switches are not possible in interrupt service routines.
 *
 * Please note: *ets_post* is executed in interrupt context
 */
uint32_t IRAM ets_post (uint32_t prio, ETSSignal sig, ETSParam par)
{
    /* This function is executed in interrupt context */
    uint32_t ret;

    critical_enter();

    /* test whether we are in hardware timer interrupt handling routine */
    if (prio == TIMER_TASK_PRIORITY) {
        /* first call ETS system post function */
        ret = ets_post_rom (prio, sig, par);

        /* handle only pending timer events */
        if (irom_cache_enabled()) {
            ets_timer_handler_isr();
        }
    }
    else {
        /* simply call ROM ets_post function */
        ret = ets_post_rom (prio, sig, par);
    }
    /* since only timer events are handled we have to reset watch dog timer */
    if (irom_cache_enabled()) {
        system_soft_wdt_feed();
    }

    if (ets_thread) {
        thread_flags_set((thread_t*)ets_thread, THREAD_FLAG_ETS_THREAD);
    }<commit_msg>cpu/esp8266: fix ets_post when flash is written<commit_after>/*
 * Copyright (C) 2018 <NAME>
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 *
 * PLEASE NOTE: This file is only used in SDK version
 */

/*
 * Internally, the SDK uses its own priority-based multitasking system,
 * the *ETS*, to handle hardware components such as the WiFi interface, or to
 * implement event-driven functions such as software timers. ETS periodically
 * executes all ETS tasks with pending events in an infinite loop with the ROM
 * function *ets_run*.
 *
 * ETS doesn't process interrupts directly in interrupt service routines.
 * Instead, they use the *ets_post* ROM function to send an event to one of the
 * ETS tasks, which then processes the interrupts asynchronously. Context
 * switches are not possible in interrupt service routines.
 *
 * To use SDK functions and keep the system alive, ETS tasks with pending
 * events have to be handled. For that purpose
 *
 * - the *ets_task_func* RIOT thread with highest possible priority is used
 * - the ROM functions *ets_run* and *ets_post* are overwritten.
 *
 * The *ets_task_func* RIOT thread is waiting for a thread flag, which is set
 * by the *ets_post function* at the end of an ETS interrupt service routine.
 * The flag indicates that there are ETS tasks with pending events that need
 * to be executed. The *ets_task_func* RIOT thread then calls the *ets_run*
 * function, which performs all ETS tasks with pending events exactly once.
 *
 * Thus, when a hardware component used by the SDK triggers an interrupt, e.g.
 * the WiFi interface, the interrupt sevice routine posts an event to the ETS
 * task by calling the *ets_post* function. The overwritten version of this
 * function sets the thread flag of the *ets_task_func* thread. The thread
 * then calls function *ets_run* to process pending events.
 */

#ifdef MODULE_ESP_SDK

#define ENABLE_DEBUG 0
#include <stdio.h>

#include "irq_arch.h"
#include "mutex.h"
#include "thread.h"

#include "esp/common_macros.h"
#include "sdk/ets_task.h"
#include "sdk/sdk.h"

static uint8_t min_prio = 0;

/* helper function for *ets_run* */
uint8_t ets_highest_1_bit (uint32_t mask)
{
    __asm__ volatile ("nsau %0, %1;" :"=r"(mask) : "r"(mask));
    return 32 - mask;
}

/*
 * Perform the execution of all pending ETS tasks. This is necessary to
 * keep the underlying ETS system used by the SDK alive. It is called from
 * the RIOT thread *ets_task_func*.
 */
void IRAM ets_tasks_run (void)
{
    #if ENABLE_DEBUG
    uint32_t _entry = phy_get_mactime();
    uint32_t _exit;
    ets_printf("ets_tasks_run @%lu\n", _entry);
    #endif

    /* reset hardware watchdog here */
    system_soft_wdt_feed();

    while (1) {
        uint8_t  hbit;
        int state = irq_disable();
        hbit = ets_highest_1_bit (ets_task_exec_mask);
        if (min_prio < hbit) {
            ets_task_tcb_t* task  = &ets_task_tab[hbit-1];
            ETSEvent *      event = &task->queue[task->qposr++];
            if (task->qposr == task->qlength) {
                task->qposr = 0;
            }
            if (--task->qpending == 0) {
                ets_task_exec_mask &= ~task->maskbit;
            }
            ets_task_min_prio = hbit;
            irq_restore(state);
            task->task(event);
            ets_task_min_prio = min_prio;
        }
        else {
            irq_restore(state);
            break;
        }
    }

    #if ENABLE_DEBUG
    _exit = phy_get_mactime();
    ets_printf("ets_tasks_run @%lu for %lu us\n", _entry, _exit - _entry);
    #endif

    /* reset hardware watchdog here again */
    system_soft_wdt_feed();
}


#define THREAD_FLAG_ETS_THREAD (1 << 0)
static volatile thread_t* ets_thread = NULL;

/*
 * Thread *ets_task_func* is waiting for the thread flag THREAD_FLAG_ETS_THREAD
 * indicating that ETS tasks have pending events and need to be executed. When
 * the thread flag is set, it calls the *ets_run* function, which performs
 * all ETS tasks with pending events exactly once. The thread flag is set by
 * the *ets_post* function, which is called at the end of an ETS interrupt
 * service routine.
 */
void *ets_task_func(void *arg)
{
    (void) arg;

    ets_thread = sched_active_thread;
    while (1) {
        thread_flags_wait_one(THREAD_FLAG_ETS_THREAD);
        ets_tasks_run();
    }

    return NULL;
}

/* helper macro for *ets_post */
#define irom_cache_enabled() (*((uint32_t*)0x60000208) & (1 << 17))

/* ETS timer task priority */
#define TIMER_TASK_PRIORITY 31

/* reference to the *ets_post* ROM function */
typedef uint32_t (*ets_post_function_t)(uint32_t prio, ETSSignal sig, ETSParam par);
static ets_post_function_t ets_post_rom = (ets_post_function_t)0x40000e24;

/*
 * Overwritten version of ROM function *ets_post*.
 *
 * ETS doesn't process interrupts directly in interrupt service routines.
 * Instead, they use the *ets_post* ROM function to send an event to one of the
 * ETS tasks, which then processes the interrupts asynchronously. Context
 * switches are not possible in interrupt service routines.
 *
 * Please note: *ets_post* is executed in interrupt context
 */
uint32_t IRAM ets_post (uint32_t prio, ETSSignal sig, ETSParam par)
{
    /* This function is executed in interrupt context */
    uint32_t ret;

    critical_enter();

    /* test whether we are in hardware timer interrupt handling routine */
    if (prio == TIMER_TASK_PRIORITY) {
        /* first call ETS system post function */
        ret = ets_post_rom (prio, sig, par);

        /* handle only pending timer events */
        if (irom_cache_enabled()) {
            ets_timer_handler_isr();
        }
    }
    else {
        /* simply call ROM ets_post function */
        ret = ets_post_rom (prio, sig, par);
    }
    /* since only timer events are handled we have to reset watch dog timer */
    if (irom_cache_enabled()) {
        system_soft_wdt_feed();
    }

    if (ets_thread && irom_cache_enabled()) {
        thread_flags_set((thread_t*)ets_thread, THREAD_FLAG_ETS_THREAD);
    }
{'fraction_non_alphanumeric': 0.08731842663620043, 'fraction_numerical': 0.010771992818671455, 'mean_word_length': 3.1096579476861166, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3277453', 'n_tokens_mistral': 3978, 'n_tokens_neox': 3772, 'n_words': 1391}