Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nfc_scheduler.c Source File

nfc_scheduler.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 /**
00018  * \file nfc_scheduler.c
00019  * \copyright Copyright (c) ARM Ltd 2015
00020  * \author Donatien Garnier
00021  */
00022 
00023 #include <stddef.h>
00024 #include <stdint.h>
00025 #include <stdbool.h>
00026 
00027 #define __DEBUG__ 0
00028 #ifndef __MODULE__
00029 #define __MODULE__ "nfc_scheduler.c"
00030 #endif
00031 
00032 #include "platform/nfc_scheduler.h"
00033 
00034 void nfc_scheduler_init(nfc_scheduler_t *pScheduler, nfc_scheduler_timer_t *pTimer)
00035 {
00036     pScheduler->pNext = NULL;
00037     pScheduler->pTimer = pTimer;
00038 
00039     //Start timer
00040     nfc_scheduler_timer_start(pTimer);
00041 }
00042 
00043 #define MAX_TIMEOUT UINT32_MAX
00044 
00045 uint32_t nfc_scheduler_iteration(nfc_scheduler_t *pScheduler, uint32_t events)
00046 {
00047     while (true) {
00048         nfc_task_t *pPrioTask = NULL;
00049         nfc_task_t *pPrioTaskPrevious = NULL;
00050         uint32_t prioTaskEvent = 0;
00051         int64_t timeout;
00052         nfc_task_t *pPreviousTask = NULL;
00053         nfc_task_t *pTask = pScheduler->pNext;
00054 
00055         if (pTask == NULL) {
00056             NFC_DBG("Empty queue, %lu ms elapsed", nfc_scheduler_timer_get(pScheduler->pTimer));
00057             //Empty queue, return
00058             return MAX_TIMEOUT;
00059         }
00060 
00061         //Get timer value
00062         uint32_t timeElapsed = nfc_scheduler_timer_get(pScheduler->pTimer);
00063         NFC_DBG("%lu ms elapsed", timeElapsed);
00064         nfc_scheduler_timer_reset(pScheduler->pTimer);
00065 
00066         do {
00067             //Apply timeouts
00068             if (pTask->events & EVENT_TIMEOUT) {
00069                 pTask->timeout -= timeElapsed;
00070             }
00071             pPreviousTask = pTask;
00072             pTask = pTask->pNext;
00073         } while (pTask != NULL);
00074 
00075         pTask = pScheduler->pNext;
00076         pPreviousTask = NULL;
00077         timeout = MAX_TIMEOUT;
00078         do {
00079             //Check which task should be woken up first
00080             if ((events & EVENT_HW_INTERRUPT) && (pTask->events & EVENT_HW_INTERRUPT)) {
00081                 //Hardware interrupts have prio
00082                 pPrioTask = pTask;
00083                 pPrioTaskPrevious = pPreviousTask;
00084                 timeout = 0;
00085                 events &= ~EVENT_HW_INTERRUPT; //Only one task gets triggered per event
00086                 prioTaskEvent = EVENT_HW_INTERRUPT;
00087                 break;
00088             } else if ((pTask->events & EVENT_TIMEOUT) && (pTask->timeout < timeout)) {
00089                 pPrioTask = pTask;
00090                 pPrioTaskPrevious = pPreviousTask;
00091                 timeout = pTask->timeout;
00092                 prioTaskEvent = EVENT_TIMEOUT;
00093             }
00094             pPreviousTask = pTask;
00095             pTask = pTask->pNext;
00096         } while (pTask != NULL);
00097 
00098         if (pPrioTask == NULL) {
00099             //No task to wake up, exit
00100             NFC_DBG("No task to wake up");
00101             return MAX_TIMEOUT;
00102         }
00103 
00104         if (timeout >  0) {
00105             //No task to wake up yet
00106             if (timeout > MAX_TIMEOUT) {
00107                 NFC_DBG("No task to wake up");
00108                 return MAX_TIMEOUT;
00109             } else {
00110                 NFC_DBG("No task to wake up, wait %lu ms", timeout);
00111                 return timeout;
00112             }
00113         }
00114 
00115         //Dequeue task
00116         if (pPrioTaskPrevious == NULL) {
00117             pScheduler->pNext = pPrioTask->pNext;
00118         } else {
00119             pPrioTaskPrevious->pNext = pPrioTask->pNext;
00120         }
00121         pPrioTask->pNext = NULL;
00122 
00123         //Execute task
00124         NFC_DBG("Calling task %p - events %02X", pPrioTask, prioTaskEvent);
00125         pPrioTask->fn(prioTaskEvent, pPrioTask->pUserData);
00126         events &= ~EVENT_HW_INTERRUPT; //Only one task gets triggered per event
00127     }
00128     return MAX_TIMEOUT;
00129 }
00130 
00131 void nfc_scheduler_queue_task(nfc_scheduler_t *pScheduler, nfc_task_t *pTask)
00132 {
00133     pTask->timeout = pTask->timeoutInitial + nfc_scheduler_timer_get(pScheduler->pTimer);
00134     NFC_DBG("Queuing task %p: events %1X, timeout %lu ms", pTask, pTask->events, pTask->timeout);
00135     //Find last task
00136     nfc_task_t *pPrevTask = pScheduler->pNext;
00137     pTask->pNext = NULL;
00138     if (pPrevTask == NULL) {
00139         pScheduler->pNext = pTask;
00140         return;
00141     }
00142     while (pPrevTask->pNext != NULL) {
00143         pPrevTask = pPrevTask->pNext;
00144     }
00145     pPrevTask->pNext = pTask;
00146 }
00147 
00148 void nfc_scheduler_dequeue_task(nfc_scheduler_t *pScheduler, bool abort, nfc_task_t *pTask)
00149 {
00150     NFC_DBG("Dequeuing task %p", pTask);
00151     //Find task
00152     nfc_task_t *pPrevTask = pScheduler->pNext;
00153     if (pPrevTask == NULL) {
00154         pTask->pNext = NULL;
00155         return;
00156     }
00157     if (pPrevTask == pTask) {
00158         if (abort) {
00159             pTask->fn(EVENT_ABORTED, pTask->pUserData);
00160         }
00161         pScheduler->pNext = pTask->pNext;
00162         pTask->pNext = NULL;
00163         return;
00164     }
00165     while (pPrevTask->pNext != NULL) {
00166         if (pPrevTask->pNext == pTask) {
00167             if (abort) {
00168                 pTask->fn(EVENT_ABORTED, pTask->pUserData);
00169             }
00170             pPrevTask->pNext = pTask->pNext;
00171             pTask->pNext = NULL;
00172             return;
00173         }
00174         pPrevTask = pPrevTask->pNext;
00175     }
00176     pTask->pNext = NULL;
00177 }
00178 
00179 void task_init(nfc_task_t *pTask, uint32_t events, uint32_t timeout, nfc_task_fn fn, void *pUserData)
00180 {
00181     pTask->events = events;
00182     pTask->timeoutInitial = timeout;
00183     pTask->fn = fn;
00184     pTask->pUserData = pUserData;
00185     pTask->pNext = NULL;
00186 }