mirror of
https://github.com/manuelbl/ttn-esp32.git
synced 2024-09-28 14:13:58 +02:00
170 lines
4.8 KiB
C
170 lines
4.8 KiB
C
/*
|
|
* Copyright (c) 2014-2016 IBM Corporation.
|
|
* Copyright (c) 2016-2017, 2019 MCCI Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the <organization> nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#define LMIC_DR_LEGACY 0
|
|
|
|
#include "lmic.h"
|
|
|
|
extern const struct lmic_pinmap lmic_pins;
|
|
|
|
// RUNTIME STATE
|
|
static struct {
|
|
osjob_t* scheduledjobs;
|
|
osjob_t* runnablejobs;
|
|
} OS;
|
|
|
|
int os_init_ex (const void *pintable) {
|
|
memset(&OS, 0x00, sizeof(OS));
|
|
hal_init_ex(pintable);
|
|
if (! radio_init())
|
|
return 0;
|
|
LMIC_init();
|
|
return 1;
|
|
}
|
|
|
|
void os_init() {
|
|
if (os_init_ex((const void *)&lmic_pins))
|
|
return;
|
|
ASSERT(0);
|
|
}
|
|
|
|
ostime_t os_getTime () {
|
|
return hal_ticks();
|
|
}
|
|
|
|
// unlink job from queue, return if removed
|
|
static int unlinkjob (osjob_t** pnext, osjob_t* job) {
|
|
for( ; *pnext; pnext = &((*pnext)->next)) {
|
|
if(*pnext == job) { // unlink
|
|
*pnext = job->next;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static osjob_t** getJobQueue(osjob_t* job) {
|
|
return os_jobIsTimed(job) ? &OS.scheduledjobs : &OS.runnablejobs;
|
|
}
|
|
|
|
// clear scheduled job
|
|
void os_clearCallback (osjob_t* job) {
|
|
hal_disableIRQs();
|
|
|
|
unlinkjob(getJobQueue(job), job);
|
|
|
|
hal_enableIRQs();
|
|
}
|
|
|
|
// schedule immediately runnable job
|
|
void os_setCallback (osjob_t* job, osjobcb_t cb) {
|
|
osjob_t** pnext;
|
|
hal_disableIRQs();
|
|
|
|
// remove if job was already queued
|
|
unlinkjob(getJobQueue(job), job);
|
|
|
|
// fill-in job. Ascending memory order is write-queue friendly
|
|
job->next = NULL;
|
|
job->deadline = 0;
|
|
job->func = cb;
|
|
|
|
// add to end of run queue
|
|
for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
|
|
*pnext = job;
|
|
hal_enableIRQs();
|
|
}
|
|
|
|
// schedule timed job
|
|
void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
|
|
osjob_t** pnext;
|
|
|
|
// special case time 0 -- it will be one tick late.
|
|
if (time == 0)
|
|
time = 1;
|
|
|
|
hal_disableIRQs();
|
|
|
|
// remove if job was already queued
|
|
unlinkjob(getJobQueue(job), job);
|
|
|
|
// fill-in job
|
|
job->next = NULL;
|
|
job->deadline = time;
|
|
job->func = cb;
|
|
|
|
// insert into schedule
|
|
for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
|
|
if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
|
|
// enqueue before next element and stop
|
|
job->next = *pnext;
|
|
break;
|
|
}
|
|
}
|
|
*pnext = job;
|
|
hal_enableIRQs();
|
|
}
|
|
|
|
// execute jobs from timer and from run queue
|
|
void os_runloop () {
|
|
while(1) {
|
|
os_runloop_once();
|
|
}
|
|
}
|
|
|
|
void os_runloop_once() {
|
|
osjob_t* j = NULL;
|
|
hal_processPendingIRQs();
|
|
|
|
hal_disableIRQs();
|
|
// check for runnable jobs
|
|
if(OS.runnablejobs) {
|
|
j = OS.runnablejobs;
|
|
OS.runnablejobs = j->next;
|
|
} else if(OS.scheduledjobs && hal_checkTimer(OS.scheduledjobs->deadline)) { // check for expired timed jobs
|
|
j = OS.scheduledjobs;
|
|
OS.scheduledjobs = j->next;
|
|
} else { // nothing pending
|
|
hal_sleep(); // wake by irq (timer already restarted)
|
|
}
|
|
hal_enableIRQs();
|
|
if(j) { // run job callback
|
|
j->func(j);
|
|
}
|
|
}
|
|
|
|
// return true if there are any jobs scheduled within time ticks from now.
|
|
// return false if any jobs scheduled are at least time ticks in the future.
|
|
bit_t os_queryTimeCriticalJobs(ostime_t time) {
|
|
if (OS.scheduledjobs &&
|
|
OS.scheduledjobs->deadline - os_getTime() < time)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|