SingingCat 0
application
softirq.c
1#include "main-header.h"
2#include "softirq.h"
3#include "user_app_exe.h"
4
5#define MCULIB_SOFTIRQ_HANDLE 13
6#define MAX_SOFTIRQS 10
7
8static int hw_timer;
9static uint32_t real_irq_hertz;
10static uint8_t softirqs_enabled;
11
12typedef struct softirqdef {
13 void (*callback)(uint32_t); // if null, entry is not used
14 uint32_t hertz;
15 uint32_t opaque;
16 uint32_t timer_skip; // how many timer real irqs to skip before calling this
17 uint32_t timer_skipctr; // counter from timer_skip to zero
18 uint32_t invoke_ctr;
20
21static struct softirqdef softirqs[MAX_SOFTIRQS];
22
23void softirq_init() {
24 memset(softirqs, 0, sizeof(softirqs));
25 softirqs_enabled = 0;
26 real_irq_hertz = 0;
27}
28
29static struct softirqdef *find_free() {
30 int i;
31
32 for (i = 0; i < MAX_SOFTIRQS; i++) {
33 struct softirqdef *res = &softirqs[i];
34 if (res->callback == NULL) {
35 return res;
36 }
37 }
38 return NULL;
39}
40
41static void softirq_real_irq() {
42 int i;
43
44 for (i = 0; i < MAX_SOFTIRQS; i++) {
45 struct softirqdef *res = &softirqs[i];
46 void (*c)(uint32_t);
47 c = res->callback;
48 if (c == NULL) {
49 continue;
50 }
51 if (res->timer_skipctr <= 1) {
52 res->timer_skipctr = res->timer_skip;
53 set_in_app(1); // too slow
54 res->invoke_ctr++;
55 c(res->opaque);
56 set_in_app(0); // too slow
57 continue;
58 }
59 res->timer_skipctr--;
60 }
61}
62
63int softirq_set_real_frequency(uint32_t hertz) {
64 int r;
65
66 if (hertz == real_irq_hertz) {
67 return 0;
68 }
69 if (hertz == 0) {
70 printf("[softirq] disabling timer %i\r\n", hw_timer);
71 r = mculib_timer_disable(MCULIB_SOFTIRQ_HANDLE, hw_timer);
72 if (r != 0) {
73 printf("[softirq] failed to disable timer %i: %i\r\n", hw_timer, r);
74 } else {
75 printf("[softirq] disabled timer %i: %i\r\n", hw_timer);
76 real_irq_hertz = 0;
77 return 0;
78 }
79 }
80 // leds use either timer 1 or timer 3
81 int timer = 1;
82
83 if (config_get_flag(CONFIG_FLAGS_LEDEXTERN)) {
84 timer = 3;
85 }
86 hw_timer = timer;
87
88 printf("[softirq] changing frequency of timer %i to %iHz\r\n", hw_timer, hertz);
89 r = mculib_timer_enable_simple(MCULIB_SOFTIRQ_HANDLE, timer, hertz, &softirq_real_irq);
90 if (r != 0) {
91 printf("[softirq] failed to change timer: %i\r\n", r);
92 return 1;
93 }
94
95 real_irq_hertz = hertz;
96 return 0;
97}
98
99
100void softirqs_removeall() {
101 softirqs_enabled = 0;
102 int i;
103
104 for (i = 0; i < MAX_SOFTIRQS; i++) {
105 struct softirqdef *res = &softirqs[i];
106 res->callback = NULL;
107 }
108 softirq_set_real_frequency(0);
109 softirqs_enabled = 1;
110}
111
112
113
114// calculate timer_skip values based on current "real_irq_hertz"
115void softirq_calc_settings() {
116 int i;
117
118 for (i = 0; i < MAX_SOFTIRQS; i++) {
119 struct softirqdef *res = &softirqs[i];
120 if (res->callback == NULL) {
121 continue;
122 }
123 res->timer_skip = real_irq_hertz / res->hertz;
124 res->timer_skipctr = res->timer_skip;
125 }
126}
127
128void print_softirqs() {
129 int i;
130
131 printf("[softirq] Hardware IRQ, timer %i, running at %iHz, enabled=%i\r\n", hw_timer, real_irq_hertz, softirqs_enabled);
132 int j = 0;
133
134 for (i = 0; i < MAX_SOFTIRQS; i++) {
135 struct softirqdef *res = &softirqs[i];
136 if (res->callback == NULL) {
137 continue;
138 }
139 j++;
140 printf("[softirq] IRQ #%i running at %iHz, skip=%i, skipctr=%i,opaque=%i,invoked=%i\r\n", i, res->hertz, res->timer_skip, res->timer_skipctr, res->opaque, res->invoke_ctr);
141 }
142 ;
143 printf("[softirq] %i softirqs active\r\n", j);
144}
145
146
147
148// add a softirq callback
149int softirq_timer(uint32_t hertz, uint32_t opaque, void (*callback)(uint32_t)) {
150 printf("[softirq] adding irq with %iHz (hardware timer @%iHz)\r\n", hertz, real_irq_hertz);
151 struct softirqdef *sid = find_free();
152
153 if (sid == NULL) {
154 printf("[softirq] could not add irq: maximum softirq entries (%i) exceeded\r\n", MAX_SOFTIRQS);
155 return 1;
156 }
157 softirqs_enabled = 0;
158 // TODO: implement an LCM here
159 // example: https://www.geeksforgeeks.org/program-to-find-lcm-of-two-numbers/
160 if (hertz > real_irq_hertz) {
161 if (softirq_set_real_frequency(hertz) != 0) {
162 printf("[softirq] could not add irq: failed to set hardware irq to %iHz\r\n", sid->hertz);
163 softirqs_enabled = 1;
164 return 2;
165 }
166 }
167
168 sid->callback = callback;
169 sid->hertz = hertz;
170 sid->opaque = opaque;
171 sid->invoke_ctr = 0;
172 softirq_calc_settings();
173 softirqs_enabled = 1;
174 printf("[softirq] added irq with %iHz (opaque=%i)\r\n", sid->hertz, sid->opaque);
175 return 0;
176}