krnl 1
Loading...
Searching...
No Matches
krnl.c
Go to the documentation of this file.
1#include "krnl.h"
2#if (KRNL_VRS != 20250606)
3#error "KRNL VERSION NOT UPDATED in krnl.c "
4#endif
5
6/*******************************************************
7* JDN:DCL auth plain C RT Arduino lib *
8* *
9 * *
10 * | |/ /___| _ \| \ | | ___| | *
11 * | ' // _ \ |_) | \| |/ _ \ | *
12 * | . \ __/ _ <| |\ | __/ |___ *
13 * |_|\_\___|_| \_\_| \_|\___|_____| *
14 * *
15 * *
16 * you are watching krnl.c *
17 * *
18 * March 2015,2016,..,2018 *
19 * Author: jdn *
20 * Apr. 2023 *
21 *. *
22
23 (C) 2012,2013,2014
24 2017,2018,2019,2021,2022,2023,..25
25
26
27 IF YOU ARE LUCKY LOOK HERE
28
29 https://github.com/jdn-aau/krnl
30
31
32
33 Jens Dalsgaard Nielsen <jdn@es.aau.dk>
34 http://es.aau.dk/staff/jdn
35 Section of Automation & Control
36 Aalborg University,
37 Denmark
38
39 "THE BEER-WARE LICENSE" (frit efter PHK)
40 <jdn@es.aau.dk> wrote this file. As long as you
41 retain this notice you can do whatever you want
42 with this stuff. If we meet some day, and you think
43 this stuff is worth it ...
44 you can buy me a beer in return :-)
45 or if you are real happy then ...
46 single malt will be well received :-)
47
48 Use it at your own risk - no warranty
49
50 nice info...
51 http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
52 at 20090611
53 - k_eat_time now eats time in quants of krnl tick speed but not one quant
54boundary
55 - added k_malloc and k_free
56 k_free dont free memory bq we do not want fragmentation
57 so DONT USE k_free
58 - k_malloc and k_free are weak functions so you can just add your own
59versions
60 - watchdog is enabled (2sec and reset in krnl timer) in weak function
61k_enable_wdt
62
63************************************************************************/
64/*
65
66FOR OLD HISTORY
67
68328 variants now use TIMER 2
692560 variants use TIMER 5
70https://www.arduinoslovakia.eu/application/timer-calculator
71xxxxxxxxxxxxxxxxxxxxxx
72
73328, 328P timer 2
74// AVR Timer CTC Interrupts Calculator
75// v. 8
76// http://www.arduinoslovakia.eu/application/timer-calculator
77// Microcontroller: ATmega328P
78// Created: 2025-05-09T09:12:42.511Z
79
80#define ledPin 13
81
82void setupTimer2() {
83 noInterrupts();
84 // Clear registers
85 TCCR2A = 0;
86 TCCR2B = 0;
87 TCNT2 = 0;
88
89 // 1000 Hz (16000000/((124+1)*128))
90 OCR2A = 124;
91 // CTC
92 TCCR2A |= (1 << WGM21);
93 // Prescaler 128
94 TCCR2B |= (1 << CS22) | (1 << CS20);
95 // Output Compare Match A Interrupt Enable
96 TIMSK2 |= (1 << OCIE2A);
97 interrupts();
98}
99
100void setupTimer5() {
101 noInterrupts();
102 // Clear registers
103 TCCR5A = 0;
104 TCCR5B = 0;
105 TCNT5 = 0;
106
107 // 1000 Hz (16000000/((249+1)*64))
108 OCR5A = 249;
109 // CTC
110 TCCR5B |= (1 << WGM52);
111 // Prescaler 64
112 TCCR5B |= (1 << CS51) | (1 << CS50);
113 // Output Compare Match A Interrupt Enable
114 TIMSK5 |= (1 << OCIE5A);
115 interrupts();
116}
117
118*/
119
120
121
122#ifdef WDT_TIMER
123#include <avr/wdt.h>
124#endif
125
126#include <stdlib.h>
127//#define NULL (int)0
128
129#include <avr/interrupt.h>
130
131// CPU frequency
132#if (F_CPU == 8000000)
133#pragma message("krnl detected 8 MHz we are stopping")
134#error stopping
135#endif
136
137
138 //---------------------------------------------------------------------------
139 // KRNL VARIABLES
140 // KRNL VARIABLES
141 //---------------------------------------------------------------------------
142
143 struct k_t *task_pool, // array of descriptors for tasks
144 *sem_pool, // .. for semaphores
145 AQ, // Q head for active Q
146 *pmain_el, // procesdecriptor for main eq dummy
147 *pAQ, // head of activeQ (AQ)
148 *pRun, // who is running ?
149 *pSleepSem; // one semaphor for all to sleep at
150
151struct k_msg_t *send_pool; // ptr to array for msg sem pool
152
153int k_task, k_sem, k_msg; // From k_init
154char nr_task = 0, nr_sem = 0, nr_send = 0; // counters for created elements
155
156volatile char k_running = 0, k_err_cnt = 0;
157
158volatile unsigned char tcntValue; // counters for timer system
159
160//time
161unsigned long k_millis_counter = 0;
162unsigned int k_tick_size;
163
164
165// coop multitasking
166unsigned char k_coopFlag = 0;
167
168int tmr_indx; // for travelling Qs in tmr isr
169
170
171//---------------------------------------------------------------------------
172// WDT
173//---------------------------------------------------------------------------
174
175#ifdef WDT_TIMER
176#include <avr/wdt.h>
177
178volatile char k_wdt_enabled = 1;
179
180#endif
181
182
183//---------------------------------------------------------------------------
184// Queue OPerations (activeQ, semQ,...)
185//---------------------------------------------------------------------------
186
187//---QOPS--- double chained lists with qhead as a element
188/* -<------<-------<--------<---------<------------<-
189* | |
190* \/ |
191* QHEAD (next)-->first-elm (next)-->next-elm(next) --|
192* ^ ^
193* ------------(pred) -----------(pred) char
194*
195*/
196
197// add element in end of Q ==just "before" q-head
198
199void enQ(struct k_t *Q, struct k_t *el) {
200 el->next = Q;
201 el->pred = Q->pred;
202 Q->pred->next = el;
203 Q->pred = el;
204}
205
206// remove element from a queue
207
208struct k_t *deQ(struct k_t *el) {
209 el->pred->next = el->next;
210 el->next->pred = el->pred;
211
212 return (el);
213}
214
215// insert element in Q acc to priority (1 ==highest prio)
216
217void prio_enQ(struct k_t *Q, struct k_t *el) {
218
219
223
224 char prio = el->prio;
225
226 Q = Q->next; // bq first elm is Q head itself
227
228 while (Q->prio <= prio) // find place before next with lower prio
229 {
230 Q = Q->next;
231 }
232
233 el->next = Q; // insert before element referred by Q
234 el->pred = Q->pred;
235 Q->pred->next = el;
236 Q->pred = el;
237}
238
239/***** eat time ***/
240/* real eat time so if you are blocked by higher priority task
241the blockug time do not count
242Can be use for simulate CPU usage
243*/
244void delayMicroseconds(unsigned int t);
245
246void k_eat_msec(unsigned int eatTime) {
247 while (10 < eatTime) {
248 delayMicroseconds(10000);
249 eatTime -= 10;
250 }
251 delayMicroseconds(eatTime * 1000);
252}
253
254//---HW timer IRS--timer section------------------------
255
256/*
257 The KRNL Timer is driven by timer
258
259 Install the Interrupt Service Routine (ISR) for Timer2 overflow.
260 This is normally done by writing the address of the ISR in the
261 interrupt vector table but conveniently done by using ISR()
262
263 Timer2 reload value, globally available
264*/
265
266
267/* from wiring.c
268 // the prescaler is set so that timer0 ticks every 64 clock cycles, and the
269 // the overflow handler is called every 256 ticks.
270 #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 *
271 256))
272
273 // the whole number of milliseconds per timer0 overflow
274 #define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
275
276 // the fractional number of milliseconds per timer0 overflow. we shift right
277 // by three to fit these numbers into a byte. (for the clock speeds we care
278 // about - 8 and 16 MHz - this doesn't lose precision.)
279 #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
280 #define FRACT_MAX (1000 >> 3) which is
281
282*/
283int k_ticksize(void) {
284 return k_tick_size;
285}
286
288
289//----------------------------------------------------------------------------
290// inspired from ...
291// http://arduinomega.blogspot.dk/2011/05/timer2-and-overflow-interrupt-lets-get.html
292// Inspiration from
293// http://popdevelop.com/2010/04/mastering-timer-interrupts-on-the-arduino/
294// Inspiration from "Multitasking on an AVR" by Richard Barry, March 2004
295// and http://www.control.aau.dk/~jdn/kernels/krnl/
296//----------------------------------------------------------------------------
297// avrfreaks.net
298// and my old kernel from last century
299// and a lot other stuff
300// basic concept from my own very old kernels dated back bef millenium
301
302void __attribute__((naked, noinline)) ki_task_shift(void) {
303 PUSHREGS(); // push task regs on stak so we are rdy to task shift
304 K_CHG_STAK(); // find taskstak for task in front of activeQ
305 POPREGS(); // restore regs
306 RETI(); // and do a reti NB this also enables interrupt !!!
307}
308
309#ifdef BACKSTOPPER
310void jumper() {
311
312 while (1) {
313 (*(pRun->pt))(); // call task
314 // you can just jump back to task, but your local vars in
315 // the task body will be wiped out
316 // or
317 // just hanging here
318
319#ifdef STOP_IN_BACKSTOPPER
320 k_set_prio(ZOMBI_PRIO); // priority lower than dummy so you just stops
321 while (1)
322 ; // just in case
323#endif
324 }
325}
326#endif
327
328struct k_t *k_crt_task(void (*pTask)(void), char prio, char *pStk,
329 int stkSize) {
330 struct k_t *pT;
331
332 int i;
333 char *s;
334
335 // sanity chek
336 if ((k_running) || ((prio <= 0) || (DMY_PRIO <= prio)) || (k_task <= nr_task)) {
337 goto badexit;
338 }
339
340 if (pStk == NULL) { // you didnt give me a stack
341 goto badexit;
342 }
343
344 pT = task_pool + nr_task; // lets take a task descriptor
345 pT->nr = nr_task;
346 nr_task++;
347
348 pT->cnt2 = 0; // no time out running on you for the time being
349 pT->cnt3 = 0; // no time out semaphore for you
350
351 pT->cnt1 = (int)(pStk); // ref to my stack
352
353
354 // ----- HW DEPENDENT START --------------
355 // ----- HW DEPENDENT START --------------
356
357 // paint stack with hash code to be used by k_unused_stak()
358 for (i = 0; i < stkSize; i++) {
359 pStk[i] = STAK_HASH;
360 }
361
362 s = pStk + stkSize - 1; // now we point on top of stak
363 *(s--) = 0x00; // 1 byte safety distance :-)
364
365 // an interrupt do only push PC on stack by HW - can be 2 or 3 bytes
366 // depending of 368/.../1280/2560
367#ifdef BACKSTOPPER
368 pT->pt = pTask;
369 *(s--) = lo8(jumper); // so top now holds address of function
370 *(s--) = hi8(jumper); // which is code body for task
371#else
372 *(s--) = lo8(pTask); // so top now holds address of function
373 *(s--) = hi8(pTask); // which is code body for task
374#endif
375 // NB NB 2560 use 3 byte for call/ret addresses the rest only 2
376#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
377 *(s--) = EIND; // best guess : 3 byte addresses !!! or just 0
378#endif
379
380 // r1 is the socalled zero value register
381 // see https://gcc.gnu.org/wiki/avr-gcc
382 // can tmp be non zero (multiplication etc)
383 *(s--) = 0x00; // r1
384 *(s--) = 0x00; // r0
385 *(s--) = 0x00; // sreg
386
387 // 1280 and 2560 need to save rampz reg just in case
388#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
389 *(s--) = RAMPZ; // best guess 0x3b
390#endif
391
392#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2561__)
393 *(s--) = EIND; // best guess 0x3c
394#endif
395
396 // rest of the resg on the stack
397 for (i = 0; i < 30; i++) // r2-r31 = 30 regs
398 {
399 *(s--) = 0x00;
400 }
401
402 pT->sp_lo = lo8(s); // now we just need to save stakptr
403 pT->sp_hi = hi8(s); // in thread descriptor
404
405 // ----- HW DEPENDENT ENDE --------------
406 // ----- HW DEPENDENT ENDE --------------
407 // ----- HW DEPENDENT ENDE --------------
408
409 pT->prio = prio;
410 pT->maxv = (int)prio; // maxv for holding org prio for inheritance
411 prio_enQ(pAQ, pT); // and put task in active Q
412
413 return (pT);
414
415badexit:
416 k_err_cnt++;
417 return (NULL);
418}
419
420int freeRam(void) {
421 extern int __heap_start, *__brkval;
422 int x, v;
423 // NASTY
424 x = ((int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval)); // to remove warning
425 return x;
426 // hw specific :-/
427 // return ((int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval));
428
429 /* from
430 http://www.noah.org/wiki/Arduino_notes#debug_memory_problems_.28out_of_RAM.29
431 int freeRam () {
432 // __brkval is the address of the top of the heap if memory has been
433 allocated.
434 // If __brkval is zero then it means malloc has not used any memory yet, so
435 // we look at the address of __heap_start.
436 extern int __heap_start
437 extern int *__brkval; // address of the top of heap
438 int stack_top;
439 return (int)&stack_top - ((int)__brkval == 0 ? (int)&__heap_start :
440 (int)__brkval);
441 }
442 */
443}
444
445int k_sleep(int time) {
446 int r;
447 if (time <= 0)
448 return -1;
449 r = k_wait(pSleepSem, time);
450 if (r == -1) // timeout ? yes :-)
451 return 0;
452 return -1; // should not occur
453}
454
456 int i;
457 char *pstk;
458
459 pstk = (char *)(pRun->cnt1);
460
461 // look for stack paint
462 i = 0;
463 while (*pstk == STAK_HASH) {
464 pstk++;
465 i++;
466 }
467
468 return (i);
469}
470
471
472int ki_unused_stak(struct k_t *t) {
473 int i;
474 char *pstk;
475
476 if (t) // another task or yourself - NO CHK of validity !!!!!
477 {
478 pstk = (char *)(t->cnt1);
479 } else {
480 pstk = (char *)(pRun->cnt1);
481 }
482
483 // look for stack paint
484 i = 0;
485 while (*pstk == STAK_HASH) {
486 pstk++;
487 i++;
488 }
489
490 return (i);
491}
492
493int k_unused_stak(struct k_t *t) {
494 int i;
495
496 DI();
497 i = ki_unused_stak(t);
498 EI();
499 return (i);
500}
501
502
503int k_set_prio(char prio) {
504 int i;
505
506 if (!k_running) {
507 return (-2);
508 }
509
510 DI();
511
512 if ((prio <= 0) || (DMY_PRIO <= prio)) // not legal value my friend
513 {
514 EI();
515 return (-1);
516 }
517 i = pRun->prio;
518
519 pRun->prio = prio;
520
521 prio_enQ(pAQ, deQ(pRun));
523
524 EI();
525
526 return (i);
527}
528
529int k_mut_ceil_set(struct k_t *sem, char prio) {
530 // NB NB assume semaphore is created prior to this call
531 // NO CHECK - no mercy !!!
532 // work only BEFORE k_start
533 if (k_running) {
534 return (-2); // bad bad
535 }
536
537 if ((prio <= 0) || (DMY_PRIO <= prio)) {
538 return (-1); // bad bad
539 }
540 sem->ceiling_prio = prio;
541 return 0; // OK
542}
543
544struct k_t *k_crt_sem(int init_val, int maxvalue) {
545 struct k_t *sem;
546
547 if (k_running) {
548 return (NULL);
549 }
550
551 if ((maxvalue < init_val)
552 || (MAX_SEM_VAL < maxvalue)
553 || (init_val < 0)
554 || (maxvalue < 0)) {
555 goto badexit;
556 }
557
558 if (k_sem <= nr_sem) // no vacant in buf
559 {
560 goto badexit;
561 }
562
563 sem = sem_pool + nr_sem; // allocate it
564 sem->nr = nr_sem;
565 nr_sem++;
566
567 sem->cnt2 = 0; // no timer running
568 sem->next = sem->pred = sem; // point at myself == no one in Q
569 sem->prio = QHD_PRIO;
570 sem->cnt1 = init_val;
571
572 sem->maxv = maxvalue;
573 sem->clip = 0;
574
575 sem->ceiling_prio = -1; // to indicate it is not active
576 sem->saved_prio = -1;
577
578 return (sem);
579
580badexit:
581 k_err_cnt++; // one more error so krnl will not start
582
583 return (NULL);
584}
585
586int k_set_sem_timer(struct k_t *sem, int val) {
587 // there is no k_stop_sem_timer fct just call with val== 0 for stopping timer
588 // fct
589
590 if (val < 0) {
591 return -1;
592 }
593
594 DI();
595 if (0 <= sem->cnt1) {
596 sem->cnt1 = 0; // reset
597 }
598
599 sem->cnt2 = sem->cnt3 = val; // if 0 then timer is not running -
600 EI();
601
602 return (0);
603}
604
605int ki_signal(struct k_t *sem) {
606 DI(); // just in case
607 if (sem->cnt1 < sem->maxv) {
608
609 sem->cnt1++; // Salute to Dijkstra
610
611#ifdef KRNLBUG
612 k_sem_signal(sem->nr, sem->cnt1); // call to breakout functino
613#endif
614
615 if (sem->cnt1 <= 0) {
616 sem->next->cnt2 = 0; // return code == ok in waiting tasks pocket(cnt2)
617 prio_enQ(pAQ, deQ(sem->next));
618 return (0); // a task was waiting and is now in AQ
619 } else {
620 return (1); // just delivered a signal - no task was waiting
621 }
622 } // CLIP :-(
623 else {
624 if (sem->clip < MAX_SEM_VAL + 1) {
625 sem->clip++;
626 }
627 // here we are on bad clip failure no signal takes place
628 // signal is lost !!!
629#ifdef KRNLBUG
630 k_sem_clip(sem->nr, sem->clip);
631#endif
632 return (-1);
633 }
634}
635
636int k_signal(struct k_t *sem) {
637 int res;
638
639 DI();
640
641 res = ki_signal(sem); // 1: ok no task to AQ, 0: ok task to AQ
642
643 if (res == 0) {
644 ki_task_shift(); // bq maybe started task has higher prio than me
645 }
646
647 EI();
648
649 return (res);
650}
651
652/* normally ki_wait should not be used by user */
653int ki_wait(struct k_t *sem, int timeout) {
654 DI();
655
656 if (0 < sem->cnt1) {
657 sem->cnt1--; // Salute to Dijkstra
658 return (1); // ok: 1 bq we are not suspended
659 }
660
661 if (timeout < 0) // no luck, dont want to wait so bye bye
662 {
663 return (-1); // will not wait so bad luck
664 }
665 // from here we want to wait
666 pRun->cnt2 = timeout; // 0 == wait forever
667
668 if (timeout) { // so we can be removed if timeout occurs
669 pRun->cnt3 = (int)sem; // nasty keep ref to semaphore in task stomach
670 }
671
672 sem->cnt1--; // Salute to Diocjkstra
673
674 enQ(sem, deQ(pRun));
676
677 // back again - have semaphore received signal or timeout ?
678 pRun->cnt3 = 0; // reset ref to timer semaphore
679
680 return ((char)(pRun->cnt2)); // 0: ok , -1: timeout
681}
682
683int k_wait(struct k_t *sem, int timeout) {
684 int retval;
685 DI();
686 retval = ki_wait(sem, timeout);
687 EI();
688 return retval; // 0: ok, -1: timeout
689}
690
691int k_wait2(struct k_t *sem, int timeout, int *nrClip) {
692 int retval;
693 DI();
694 retval = ki_wait(sem, timeout);
695 if (nrClip) {
696 *nrClip = sem->clip;
697 sem->clip = 0;
698 }
699 EI();
700 return retval; // 0: ok, -1: timeout
701}
702
703struct k_t *k_crt_mut(char ceiling_prio, int init_val, int maxvalue) {
704 struct k_t *mut;
705
706 if (k_running) {
707 return (NULL);
708 }
709
710 if (ceiling_prio < 0) {
711 k_err_cnt++;
712 return NULL;
713 }
714
715 mut = k_crt_sem(init_val, maxvalue);
716
717 if (mut == NULL) {
718 k_err_cnt++;
719 return NULL;
720 }
722
723 return mut;
724}
725
726int k_mut_ceil(struct k_t *sem, int timeout, void (*fct)(void)) {
727 int r;
728 r = k_mut_ceil_enter(sem, timeout);
729 if (r < 0) {
730 return r; // bad bad
731 }
732
733 (*fct)(); // call mutex function
734
736 return r;
737}
738
739int k_mut_ceil_enter(struct k_t *sem, int timeout) {
740 int retval;
741 DI();
742
743 if (sem->ceiling_prio < 0) {
744 EI();
745 return CEILINGFAILNOTCEIL;
746 }
747
748 if (pRun->prio < sem->ceiling_prio) { // I have higher priority than ceiling :-(
749 EI();
750 return CEILINGFAILPRIO;
751 }
752 // now we play imm ceiling protocol
753 sem->saved_prio = pRun->prio; // do im ceiling
754 pRun->prio =
755 sem->ceiling_prio; // dont need to reinsert in AQ bq ceil prio is higher
756 // or equal to mine and Im already in front of AQ
757 prio_enQ(pAQ, deQ(pRun)); // resinsert me in AQ acc to nwe(old) priority
758 retval = ki_wait(sem, timeout);
759 // coming back interrupt is still disabled !
760
761 // chk if we did get semaphore
762 if (retval < 0) { // NOPE we did not
763 pRun->prio = sem->saved_prio; // reset to my old priority
764 prio_enQ(pAQ, deQ(pRun)); // reinsert me in AQ acc to nwe(old) priority
765 ki_task_shift(); // bq maybe started task has higher prio than me
766 }
767 EI();
768 return retval; // 0(has waited),1(straight through) : ok, -1: timeout
769}
770
772 int res;
773
774 DI();
775 res = ki_signal(sem); // 1: ok no task to AQ, 0: ok task to AQ
776
777 // coming back interrupt is still disabled !
778 pRun->prio = sem->saved_prio; // reset to my old priority
779
780 prio_enQ(pAQ, deQ(pRun)); // resinsert me in AQ acc to nwe(old) priority
781
782 ki_task_shift(); // bq maybe started task has higher prio than me
783
784 EI();
785
786 return (res);
787}
788
790 int x;
791
792 DI();
793
794 x = sem->clip;
795 sem->clip = 0;
796
797 EI();
798 return x;
799}
800
801int ki_semval(struct k_t *sem) {
802 DI(); // dont remove this - bq k_semval depends on it
803
804 return (sem->cnt1);
805}
806
807int k_semval(struct k_t *sem) {
808 int v;
809 v = ki_semval(sem);
810 EI();
811 return v;
812}
813
814int k_clear_sem(struct k_t *sem) {
815 DI();
816 if (0 <= sem->cnt1) {
817 sem->cnt1 = sem->clip = 0;
818 EI();
819 return 0;
820 }
821 else {
822 EI();
823 return -1;
824
825 }
826}
827
828int ki_msg_count(struct k_msg_t *m) {
829 DI(); // dont remove this - bq k_semval depends on it
830 return m->cnt;
831}
832
833int k_msg_count(struct k_msg_t *m) {
834 int v;
835 // not needed to DI - its in ki_msg_count ... DI ();
836 v = ki_msg_count(m);
837 EI();
838 return v;
839}
840
841struct k_msg_t *k_crt_send_Q(int nr_el, int el_size, void *pBuf) {
842 struct k_msg_t *pMsg;
843
844 if (k_running) {
845 return (NULL);
846 }
847
848 if (k_msg <= nr_send) {
849 goto errexit;
850 }
851
852 if (k_sem <= nr_sem) {
853 goto errexit;
854 }
855
857 pMsg->nr = nr_send; // I am element nr nr_send in msgQ pool
858 nr_send++;
859
860 pMsg->sem =
861 k_crt_sem(0, nr_el); // we are using a sem for sync part snd <-> rcv
862
863 if (pMsg->sem == NULL) {
864 goto errexit;
865 }
866
867 pMsg->pBuf = (char *)pBuf;
868 pMsg->r = pMsg->w = -1;
869 pMsg->el_size = el_size;
870 pMsg->nr_el = nr_el;
871 pMsg->lost_msg = 0;
872 pMsg->cnt = 0; // count nr elm in Q
873
874 return (pMsg);
875
876errexit:
877 k_err_cnt++;
878 return (NULL);
879}
880
881
882int ki_clear_msg_Q(struct k_msg_t *pB) {
883 int ret;
884 if (k_running) {
885 return -2;
886 }
887
888 ret = pB->cnt;
889 if (0 < ret) { // messages pending s0
890 pB->lost_msg = 0;
891 pB->cnt = 0; // reset
892 pB->r = pB->w = -1;
893 // clear sem - can do it bq no one is waiting bq 0 < ret == pending
894 // messages
895 pB->sem->cnt1 = 0; // Serious NASTY
896 }
897 return ret;
898}
899
900int k_clear_msg_Q(struct k_msg_t *pB) {
901 int r;
902 DI();
903 r = ki_clear_msg_Q(pB);
904 EI();
905 return r;
906}
907
908char ki_send(struct k_msg_t *pB, void *el) {
909
910 int i;
911 char *pSrc, *pDst;
912
913 if (pB->nr_el <= pB->cnt) {
914 // nope - no room for a putting new msg in Q ?
915 if (pB->lost_msg < MAX_SEM_VAL) {
916 pB->lost_msg++;
917 }
918#ifdef KRNLBUG
919 k_send_Q_clip(pB->nr, pB->lost_msg);
920#endif
921 return (-1); // nope
922 } else {
923
924 pB->cnt++;
925
926 pSrc = (char *)el;
927
928 pB->w++;
929 if (pB->nr_el <= pB->w) // simple wrap around
930 {
931 pB->w = 0;
932 }
933
934 pDst = pB->pBuf + (pB->w * pB->el_size); // calculate where we shall put msg in ringbuf
935
936 for (i = 0; i < pB->el_size; i++) {
937 // copy to Q
938 *(pDst++) = *(pSrc++);
939 }
940 return (ki_signal(pB->sem)); // indicate a new msg is in Q
941 }
942}
943
944char k_send(struct k_msg_t *pB, void *el) {
945 char res;
946
947 DI();
948
949 res = ki_send(pB, el);
950 if (res == 0) // if new task in AQ == someone was waiting for msg
951 { // if 1 then nobody was waiting so no neeed for task shift
953 }
954
955 EI();
956 return (res);
957}
958
959char ki_receive(struct k_msg_t *pB, void *el, int *lost_msg) {
960 int i;
961 char r, *pSrc, *pDst;
962
963 // can be called from ISR bq no blocking
964 DI(); // just to be sure
965
966 if (0 <= (r = ki_wait(pB->sem, -1))) {
967
968 pDst = (char *)el;
969 pB->r++;
970 pB->cnt--; // got one
971
972 if (pB->nr_el <= pB->r) {
973 pB->r = 0;
974 }
975
976 pSrc = pB->pBuf + pB->r * pB->el_size;
977
978 for (i = 0; i < pB->el_size; i++) {
979 *(pDst++) = *(pSrc++);
980 }
981 if (lost_msg) {
982 *lost_msg = pB->lost_msg;
983 pB->lost_msg = 0;
984 }
985 return (r); // yes
986 }
987
988 return (-1); // nothing for you my friend
989}
990
991char k_receive(struct k_msg_t *pB, void *el, int timeout, int *lost_msg) {
992
993 int i;
994 char r, *pSrc, *pDst;
995
996 DI();
997
998 if (0 <= (r = ki_wait(pB->sem, timeout))) {
999 // yes we did get a msg :-)
1000 // ki_wait bq then intr is not enabled when coming back
1001
1002 pDst = (char *)el;
1003 pB->r++;
1004 pB->cnt--; // got one
1005
1006 if (pB->nr_el <= pB->r) {
1007 pB->r = 0;
1008 }
1009
1010 pSrc = pB->pBuf + pB->r * pB->el_size;
1011
1012 for (i = 0; i < pB->el_size; i++) {
1013 *(pDst++) = *(pSrc++);
1014 }
1015
1016 if (lost_msg) {
1017 *lost_msg = pB->lost_msg;
1018 pB->lost_msg = 0;
1019 }
1020
1021 EI();
1022 return (r); // 1 if no suspension bq msg was already present, 0: ok if you
1023 // have waited on msg
1024 }
1025
1026 EI();
1027 return (-1); // nothing for you my friend
1028}
1029
1030#ifdef READERWRITER
1031// https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem
1032
1033void k_rwInit(struct k_rwlock_t *lock) {
1034 lock->nrReaders = 0;
1035 lock->rdwrSem = k_crt_sem(1, 2);
1036 lock->rdSem = k_crt_sem(1, 2);
1037 lock->fifoSem = k_crt_sem(1, 2);
1038}
1039
1040int k_rwRdEnter(struct k_rwlock_t *lock, int timeout) {
1041 // timeout tbi later - if...
1042 k_wait(lock->fifoSem, 0);
1043 k_wait(lock->rdSem, 0);
1044
1045 lock->nrReaders++;
1046 if (lock->nrReaders == 1)
1047 k_wait(lock->rdwrSem, 0);
1048 k_signal(lock->fifoSem);
1049 k_signal(lock->rdSem);
1050}
1051
1052int k_rwWrEnter(struct k_rwlock_t *lock, int timeout) {
1053 k_wait(lock->fifoSem, 0);
1054 k_wait(lock->rdwrSem, 0);
1055 k_signal(lock->fifoSem);
1056}
1057
1058int k_rwRdLeave(struct k_rwlock_t *lock) {
1059 k_wait(lock->rdSem, 0);
1060 lock->nrReaders--;
1061 if (lock->nrReaders == 0) {
1062 k_signal(lock->rdwrSem);
1063 }
1064 k_signal(lock->rdSem);
1065}
1066
1067int k_rwWrLeave(struct k_rwlock_t *lock) {
1068 k_signal(lock->rdwrSem);
1069}
1070
1071#endif
1072
1073void k_round_robbin(void) {
1074
1075 // reinsert running task in activeQ if round robbin is selected
1076 DI();
1077
1078 prio_enQ(pAQ, deQ(pRun));
1079 ki_task_shift();
1080
1081 EI();
1082}
1083
1084void k_release(void) {
1085
1086 // let next run
1087 DI();
1088 ki_task_shift();
1089 EI();
1090}
1091
1092/* NASTY void from vrs 2001 it is main itself can be changed back
1093 */
1094
1095/*
1096 void
1097 dummy_task (void)
1098 {
1099 while (1) {
1100 k_round_robbin ();
1101 }
1102 }
1103*/
1104
1105// char dmy_stk[DMY_STK_SZ]; // dmy duty is nwo maintained by org main
1106
1107
1108int k_init(int nrTask, int nrSem, int nrMsg) {
1109 if (k_running) {
1110 return (-666);
1111 }
1113
1114 k_task = nrTask + 1; // +1 due to dummy
1115 k_sem = nrSem + nrMsg + 1; // due to that every msgQ has a builtin semaphore
1116 k_msg = nrMsg + 1; // to align so first user msgQ has index 1
1117 nr_send++; // to align so we waste one but ... better equal access
1118 task_pool = (struct k_t *)malloc(k_task * sizeof(struct k_t));
1119 sem_pool = (struct k_t *)malloc(k_sem * sizeof(struct k_t));
1120 send_pool = (struct k_msg_t *)malloc(k_msg * sizeof(struct k_msg_t));
1121
1122 // we dont accept any errors
1123 if ((task_pool == NULL) || (sem_pool == NULL) || (send_pool == NULL)) {
1124 k_err_cnt++;
1125 goto leave;
1126 }
1127 // init AQ as empty double chained list
1128 pAQ = &AQ;
1129 pAQ->next = pAQ->pred = pAQ;
1130 pAQ->prio = QHD_PRIO;
1131
1132 // crt dummy
1133 // pDmy = k_crt_task (dummy_task, DMY_PRIO, DMY_STK_SZ);
1134
1136 pmain_el->nr = 0;
1137 pmain_el->cnt2 = pmain_el->cnt3 = 0;
1138 nr_task++;
1139 pmain_el->prio = DMY_PRIO; // main is dummy
1141
1142 pSleepSem = k_crt_sem(0, 10);
1143
1144leave:
1145 return k_err_cnt;
1146}
1147
1148// https://www.arduinoslovakia.eu/application/timer-calculator
1149int k_start() {
1150
1151
1152 // will not start if errors during initialization
1153 if (k_err_cnt) {
1154 return -k_err_cnt;
1155 }
1156
1157 k_tick_size = 1;
1158
1159 DI(); // silencio
1160
1161 // 328(p) timer2
1162// 2560, 2561 timer5
1163
1164DI();
1165#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
1166// https://www.arduinoslovakia.eu/application/timer-calculator
1167#define KRNLTMR 5
1168// Clear registers
1169 TCCR5A = 0;
1170 TCCR5B = 0;
1171 TCNT5 = 0;
1172
1173 // 1000 Hz (16000000/((249+1)*64))
1174 OCR5A = 249;
1175 // CTC
1176 TCCR5B |= (1 << WGM52);
1177 // Prescaler 64
1178 TCCR5B |= (1 << CS51) | (1 << CS50);
1179 // Output Compare Match A Interrupt Enable
1180 TIMSK5 |= (1 << OCIE5A);
1181
1182#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega328__)
1183// https://www.arduinoslovakia.eu/application/timer-calculator
1184#define KRNLTMR 2
1185 // Clear registers
1186 TCCR2A = 0;
1187 TCCR2B = 0;
1188 TCNT2 = 0;
1189 OCR2A = 124; // 1000 Hz (16000000/((124+1)*128))
1190 // CTC
1191 TCCR2A |= (1 << WGM21); // Prescaler 128
1192 TCCR2B |= (1 << CS22) | (1 << CS20);
1193 TIMSK2 |= (1 << OCIE2A); // Output Compare Match A Interrupt Enable
1194#else
1195ERROR
1196#endif
1197
1198 pRun = pmain_el; // just for ki_task_shift
1199 k_running = 1;
1200
1201 ki_task_shift(); // bye bye from here
1202
1203 EI();
1204
1205 // this while loop bq main are dummy
1206 while (1) {
1207 }
1208
1209 return 0;
1210}
1211
1212int k_stop() {
1213
1214 /*
1215 main is dummy task so it gives no meaning to stop krnl this way
1216 The best and dirty thing is
1217
1218 // DANGEROUS - handle with care - no isr timer control etc etc
1219 // I WILL NEVER USE IT
1220
1221 DI();
1222 while (1);
1223
1224 */
1225
1226
1227 DI(); // silencio
1228 if (!k_running) {
1229 EI();
1230 return -1;
1231 }
1232 while (1)
1233 ; // we stuck here with intr disabled !!!
1234}
1235
1236void k_set_coop_multitask(unsigned char onn) {
1237 k_coopFlag = onn;
1238}
1239
1240unsigned long ki_millis(void) {
1241 unsigned long l;
1242 DI(); // just to be sure
1244 return l;
1245}
1246
1247unsigned long k_millis(void) {
1248 unsigned long l;
1249
1250 DI();
1252 EI();
1253 return l;
1254}
1255
1256int k_tmrInfo(void) {
1257 return (KRNLTMR);
1258}
1259
1260struct k_t *pE; // used only in ISR as "temporary var"
1261
1262#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
1263ISR(TIMER5_COMPA_vect, ISR_NAKED)
1264#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega328__)
1265ISR(TIMER2_COMPA_vect, ISR_NAKED) // naked so we have to supply with prolog and
1266 // epilog (push pop stack of regs)
1267#else
1269#endif
1270
1271{
1272 PUSHREGS(); // no local vars ! I think
1273
1275 goto exitt;
1276 }
1277
1278#ifdef WDT_TIMER
1279 if (k_wdt_enabled)
1280 wdt_reset();
1281#endif
1282
1283
1284 k_millis_counter += k_tick_size; // my own millis counter
1285
1286 // the following may look crazy: to go throuh all semaphores and tasks
1287 // but you may have 3-4 tasks and 3-6 semaphores in your code
1288 // so - seems to be efficient :-)
1289 // so - it's a good idea not to init krnl with more items
1290 // (tasks/Sem/msg descriptors than needed)
1291
1292 pE = sem_pool; // Semaphore timer - check timers on semaphores
1293
1294 // Look for timeout on semaphores
1296 if (0 < pE->cnt2) // timer on semaphore ?
1297 {
1298 pE->cnt2--; // yep decrement it
1299 if (pE->cnt2 <= 0) // timeout ?
1300 {
1301 pE->cnt2 = pE->cnt3; // preset again - if cnt3 == 0 and >= 0 the rep timer
1302 ki_signal(pE); // issue a signal to the semaphore
1303 }
1304 }
1305 pE++;
1306 }
1307
1308
1309 // Look for activ timers on tasks
1310 pE = task_pool; // Chk timers on tasks - they may be one shoot waiting
1311 for (tmr_indx = 0; tmr_indx < nr_task; tmr_indx++) {
1312 if (0 < pE->cnt2) // timer active on task ?
1313 {
1314 pE->cnt2--; // yep so let us do one down count
1315 if (pE->cnt2 <= 0) // timeout ? ( == 0 )
1316 {
1317 ((struct k_t *)(pE->cnt3))->cnt1++; // leaving sem so adjust semcount on sem
1318 prio_enQ(pAQ, deQ(pE)); // and rip task of semQ and insert in activeQ
1319 pE->cnt2 = -1; // indicate timeout has occured
1320 }
1321 }
1322 pE++;
1323 }
1324
1326 prio_enQ(pAQ, deQ(pRun)); // round robbin
1327 K_CHG_STAK(); // let first in AQ run
1328 }
1329
1330exitt:
1331
1332 POPREGS();
1334}
1335
1336
1337
1338#ifdef KRNLBUG
1339
1340// defined as weak so compiler will take yours instead of mine
1341void __attribute__((weak)) k_breakout(void) {}
1342
1343void __attribute__((weak)) k_sem_clip(unsigned char nr, int nrClip) {}
1344
1345void __attribute__((weak)) k_sem_signal(unsigned char nr, int semVal) {}
1346
1347void __attribute__((weak)) k_sem_wait(unsigned char nr, int semVal) {}
1348
1349void __attribute__((weak)) k_send_Q_clip(unsigned char nr, int nrClip) {}
1350
1351
1352#endif
1353
1354#ifdef DYNMEMORY
1355void *__attribute__((weak)) k_malloc(int k) {
1356 void *m;
1357 DI();
1358 m = malloc(k);
1359 EI();
1360 return m;
1361}
1362
1363void __attribute__((weak)) k_free(void *m) {
1364 // we dont free memory
1365}
1366#endif
1367
1368
1369void k_wdt_enable(int i) {
1370 DI();
1371 wdt_enable(i);
1372 k_wdt_enabled = 1;
1373 EI();
1374}
1375
1376void k_wdt_disable(void) {
1377 DI();
1378 k_wdt_enabled = 0;
1379 wdt_disable();
1380 EI();
1381}
1382
1383
1384/* EOF - JDN */
1385
1386/*
1387 #ifdef __cplusplus
1388 }
1389 #endif
1390*/
1391
1392
struct k_t * pTask
volatile int i
int x
void k_wdt_enable(int i)
enable HW watchdog Call wdt_enable (AVR lib) DI(); wdt_enable(WDT_PERIOD); EI(); WDT_PERIOD is in KRN...
Definition krnl.c:1369
unsigned long k_millis(void)
return no of millisec sincs start NB no leap seconds - its clean
Definition krnl.c:1247
int k_signal(struct k_t *sem)
Signal a semaphore w eventually task shift.
Definition krnl.c:636
void ki_task_shift(void)
shift running to task in front in AQ
Definition krnl.c:302
int k_msg
Definition krnl.c:153
unsigned long ki_millis(void)
returns no msec since start - no DI/EI lock Returns nr of milliseconds since krnl was started by k_st...
Definition krnl.c:1240
unsigned int k_tick_size
Definition krnl.c:162
void k_eat_msec(unsigned int eatTime)
eat milliseconds - to mimik time consuming code
Definition krnl.c:246
void k_free(void *m)
a krnl free which do nothing. call free empty - no function if dft as weak so you can supply with you...
Definition krnl.c:1363
void delayMicroseconds(unsigned int t)
int ki_semval(struct k_t *sem)
return sem counter value - Its a ki_ fct so intr is not enabled by leave
Definition krnl.c:801
char nr_send
Definition krnl.c:154
struct k_t * pRun
Definition krnl.c:148
int k_sem
Definition krnl.c:153
int k_msg_count(struct k_msg_t *m)
return no of pending messages
Definition krnl.c:833
struct k_t * pAQ
Definition krnl.c:147
void k_breakout(void)
Definition krnl.c:1341
int k_tmrInfo(void)
Definition krnl.c:1256
int k_mut_ceil_set(struct k_t *sem, char prio)
set ceiling priority on a mutex
Definition krnl.c:529
char k_receive(struct k_msg_t *pB, void *el, int timeout, int *lost_msg)
Definition krnl.c:991
int ki_signal(struct k_t *sem)
signal a semaphore from AN ISR - no task shift , do not enable intr,...
Definition krnl.c:605
void k_release(void)
Definition krnl.c:1084
int k_wait2(struct k_t *sem, int timeout, int *nrClip)
wait with add info .ยด- nr of in max limit from signals since last time(saturation)
Definition krnl.c:691
volatile unsigned char tcntValue
Definition krnl.c:158
int k_sleep(int time)
let task sleep for a number of milliseconds
Definition krnl.c:445
void k_send_Q_clip(unsigned char nr, int nrClip)
breakout for k_send
Definition krnl.c:1349
volatile char k_running
Definition krnl.c:156
int k_task
Definition krnl.c:153
struct k_t * pE
Definition krnl.c:1260
char ki_receive(struct k_msg_t *pB, void *el, int *lost_msg)
Definition krnl.c:959
struct k_t * pSleepSem
Definition krnl.c:149
int k_semval(struct k_t *sem)
as ki_semval but to enable intr after leave
Definition krnl.c:807
struct k_t * sem_pool
Definition krnl.c:144
int k_set_prio(char prio)
Definition krnl.c:503
char ki_send(struct k_msg_t *pB, void *el)
Definition krnl.c:908
int k_wait(struct k_t *sem, int timeout)
stand wait on semaphore call with timeout facility
Definition krnl.c:683
struct k_t * pmain_el
Definition krnl.c:146
int k_clear_msg_Q(struct k_msg_t *pB)
Definition krnl.c:900
int ki_unused_stak(struct k_t *t)
Definition krnl.c:472
char nr_sem
Definition krnl.c:154
void k_sem_signal(unsigned char nr, int semVal)
breakout for k_signal
Definition krnl.c:1345
int k_mut_ceil_leave(struct k_t *sem)
leave a "ceiled mutex" enter with k_mut_ceil_enter
Definition krnl.c:771
void k_set_coop_multitask(unsigned char onn)
Definition krnl.c:1236
struct k_t * k_crt_task(void(*pTask)(void), char prio, char *pStk, int stkSize)
create a task - only to be called before k_start creates a task and put it in the active Q
Definition krnl.c:328
int ki_my_unused_stak()
Definition krnl.c:455
int k_stop()
Definition krnl.c:1212
void k_round_robbin(void)
Definition krnl.c:1073
void * k_malloc(int k)
overruled malloc call malloc protected by DI and EI if dft as weak so you can supply with your own
Definition krnl.c:1355
void jumper()
Definition krnl.c:310
struct k_t * deQ(struct k_t *el)
Definition krnl.c:208
int k_set_sem_timer(struct k_t *sem, int val)
attach a periodic timer to a semaphore, to be used for realtime
Definition krnl.c:586
int k_unused_stak(struct k_t *t)
Definition krnl.c:493
char k_send(struct k_msg_t *pB, void *el)
Definition krnl.c:944
void enQ(struct k_t *Q, struct k_t *el)
Definition krnl.c:199
int k_sem_signals_lost(struct k_t *sem)
return signals lost on a sem(saturation) (and reset the saturation counter) Returns how many signals ...
Definition krnl.c:789
int freeRam(void)
Definition krnl.c:420
int k_mut_ceil_enter(struct k_t *sem, int timeout)
set ceiling priority on a mutex
Definition krnl.c:739
int tmr_indx
Definition krnl.c:168
int k_ticksize(void)
Definition krnl.c:283
int k_mut_ceil(struct k_t *sem, int timeout, void(*fct)(void))
mutex entet, call fct, leave ceil in one call
Definition krnl.c:726
struct k_t * k_crt_sem(int init_val, int maxvalue)
change task priority and reinserts it in task Q and do a task shift
Definition krnl.c:544
struct k_msg_t * send_pool
Definition krnl.c:151
struct k_t * k_crt_mut(char ceiling_prio, int init_val, int maxvalue)
crt a std semaphore to be used as mutex
Definition krnl.c:703
int k_init(int nrTask, int nrSem, int nrMsg)
Definition krnl.c:1108
struct k_msg_t * k_crt_send_Q(int nr_el, int el_size, void *pBuf)
Definition krnl.c:841
char nr_task
Definition krnl.c:154
struct k_t AQ
Definition krnl.c:145
volatile char k_err_cnt
Definition krnl.c:156
void k_wdt_disable(void)
disable HW watchdog disable wdt Disable the watchdog timer
Definition krnl.c:1376
unsigned char k_coopFlag
Definition krnl.c:166
void prio_enQ(struct k_t *Q, struct k_t *el)
Definition krnl.c:217
struct k_t * task_pool
Definition krnl.c:143
int ki_wait(struct k_t *sem, int timeout)
a wait call with no disable - fct might no be usefull
Definition krnl.c:653
void k_sem_clip(unsigned char nr, int nrClip)
Definition krnl.c:1343
int ki_msg_count(struct k_msg_t *m)
returns no of pending msg on msgf sem - a ki_ fct so no enable of interrupt
Definition krnl.c:828
int k_start()
Definition krnl.c:1149
ERROR1
Definition krnl.c:1271
int ki_clear_msg_Q(struct k_msg_t *pB)
Definition krnl.c:882
int k_clear_sem(struct k_t *sem)
reset sem counter to 0 is no tasks is waiting - usefull ?
Definition krnl.c:814
void k_sem_wait(unsigned char nr, int semVal)
breakout for k_wait
Definition krnl.c:1347
#define DI()
Definition krnl.h:478
#define CEILINGFAILPRIO
Definition krnl.h:302
#define QHD_PRIO
Definition krnl.h:290
volatile char k_wdt_enabled
#define EI()
Definition krnl.h:479
#define RETI()
Definition krnl.h:480
#define CEILINGFAILNOTCEIL
Definition krnl.h:301
#define K_CHG_STAK()
Definition krnl.h:488
#define lo8(X)
Definition krnl.h:475
#define ZOMBI_PRIO
Definition krnl.h:291
#define DMY_PRIO
Definition krnl.h:292
#define STAK_HASH
Definition krnl.h:297
#define hi8(X)
Definition krnl.h:476
#define MAX_SEM_VAL
Definition krnl.h:298
ISR(INT0_vect, ISR_NAKED)
Definition isem.ino:47
struct k_msg_t * pMsg
Definition msg1.ino:18
struct k_t * sem
Definition mutex.ino:3
unsigned long k_millis_counter
Definition krnl.c:161
char s[150]
volatile int k
Definition simpleisr.ino:7
volatile int l
Definition simpleisr.ino:7
volatile int m
Definition simpleisr.ino:7
PUSHREGS()
unsigned char nr
Definition krnl.h:346
volatile int el_size
Definition krnl.h:349
volatile int r
Definition krnl.h:350
struct k_t * sem
Definition krnl.h:347
char * pBuf
Definition krnl.h:348
volatile int w
Definition krnl.h:350
volatile int nr_el
Definition krnl.h:349
volatile int lost_msg
Definition krnl.h:349
volatile int cnt
Definition krnl.h:350
Definition krnl.h:323
volatile char sp_lo
Definition krnl.h:330
struct k_t * pred
Definition krnl.h:329
char ceiling_prio
Definition krnl.h:333
volatile int cnt2
Definition krnl.h:336
volatile int cnt1
Definition krnl.h:335
void(* pt)(void)
Definition krnl.h:325
char prio
Definition krnl.h:332
struct k_t * next
Definition krnl.h:328
volatile int maxv
Definition krnl.h:338
unsigned char nr
Definition krnl.h:327
volatile char sp_hi
Definition krnl.h:331
volatile int cnt3
Definition krnl.h:337