dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_thread.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  */
25 
26 #include "pios.h"
27 #include "pios_thread.h"
28 
29 #if !defined(PIOS_INCLUDE_CHIBIOS)
30 #error "pios_thread.c requires PIOS_INCLUDE_CHIBIOS"
31 #endif
32 
33 #if defined(PIOS_INCLUDE_CHIBIOS)
34 struct pios_thread
35 {
36  Thread *threadp;
37 };
38 
39 DONT_BUILD_IF(CH_FREQUENCY != 1000, ChFreqMs);
40 #define CVT_MS2ST(msec) (msec)
41 #define CVT_ST2MS(n) (n)
42 
43 #if 0
44 #define CVT_MS2ST(msec) ((systime_t)(((((uint32_t)(msec)) * ((uint64_t)CH_FREQUENCY) - 1UL) / 1000UL) + 1UL))
45 #define CVT_ST2MS(n) (((((n) - 1ULL) * 1000ULL) / ((uint64_t)CH_FREQUENCY)) + 1UL)
46 #endif
47 
52 static uint32_t ceil_size(uint32_t size)
53 {
54  const uint32_t a = sizeof(stkalign_t);
55  size = size + (a - size % a);
56  return size;
57 }
64 static uint8_t * align8_alloc(uint32_t size)
65 {
66  // round size up to at nearest multiple of 8 + 4 bytes to guarantee
67  // sufficient size within. This is because PIOS_malloc only guarantees
68  // uintptr_t alignment which is 4 bytes.
69  size = size + sizeof(uintptr_t);
70  uint8_t *wap = PIOS_malloc(size);
71 
72  // shift start point to nearest 8 byte boundary.
73  uint32_t pad = ((uint32_t) wap) % sizeof(stkalign_t);
74  wap = wap + pad;
75 
76  return wap;
77 }
78 
86 struct pios_thread *PIOS_Thread_WrapCurrentThread(const char *namep)
87 {
88  struct pios_thread *thread = PIOS_malloc_no_dma(sizeof(struct pios_thread));
89 
90  if (thread) {
91  thread->threadp = chThdSelf();
92 #if CH_USE_REGISTRY
93  thread->threadp->p_name = namep;
94 #endif /* CH_USE_REGISTRY */
95  }
96 
97  return thread;
98 }
99 
106 {
107  chThdSetPriority(prio);
108 }
109 
123 struct pios_thread *PIOS_Thread_Create(void (*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
124 {
125  struct pios_thread *thread = PIOS_malloc_no_dma(sizeof(struct pios_thread));
126  if (thread == NULL)
127  return NULL;
128 
129  // Use special functions to ensure ChibiOS stack requirements
130  stack_bytes = ceil_size(stack_bytes);
131  uint8_t *wap = align8_alloc(stack_bytes);
132  if (wap == NULL)
133  {
134  PIOS_free(thread);
135  return NULL;
136  }
137 
138  thread->threadp = chThdCreateStatic(wap, stack_bytes, prio, (msg_t (*)(void *))fp, argp);
139  if (thread->threadp == NULL)
140  {
141  PIOS_free(thread);
142  PIOS_free(wap);
143  return NULL;
144  }
145 
146 #if CH_USE_REGISTRY
147  thread->threadp->p_name = namep;
148 #endif /* CH_USE_REGISTRY */
149 
150  return thread;
151 }
152 
153 #if (CH_USE_WAITEXIT == TRUE)
154 
161 void PIOS_Thread_Delete(struct pios_thread *threadp)
162 {
163  if (threadp == NULL)
164  {
165  chThdExit(0);
166  }
167  else
168  {
169  chThdTerminate(threadp->threadp);
170  chThdWait(threadp->threadp);
171  }
172 }
173 #else
174 #error "PIOS_Thread_Delete requires CH_USE_WAITEXIT to be defined TRUE"
175 #endif /* (CH_USE_WAITEXIT == TRUE) */
176 
184 uint32_t PIOS_Thread_Systime(void)
185 {
186  return (uint32_t)CVT_ST2MS(chTimeNow());
187 }
188 
196 void PIOS_Thread_Sleep(uint32_t time_ms)
197 {
198  if (time_ms == PIOS_THREAD_TIMEOUT_MAX)
199  chThdSleep(TIME_INFINITE);
200  else
201  chThdSleep(MS2ST(time_ms));
202 }
203 
213 void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
214 {
215  // Do the math in the millisecond domain.
216  *previous_ms += increment_ms;
217 
218  systime_t future = CVT_MS2ST(*previous_ms);
219  systime_t increment_st = CVT_MS2ST(increment_ms);
220 
221  chSysLock();
222 
223  systime_t now = chTimeNow();
224  systime_t sleep_time = future - now;
225 
226  if (sleep_time > increment_st) {
227  // OK, the calculated sleep time is much longer than
228  // the desired interval. There's two possibilities:
229  // 1) We were already late! If so just don't sleep.
230  // 2) The timer wrapped. (at 49 days) Just don't sleep.
231 
232  if ((now - future) > increment_st) {
233  // However, in this particular case we need to fix up
234  // the clock. If we're very late, OR WRAPPED,
235  // don't try and keep on the previous timebase.
236  *previous_ms = CVT_ST2MS(now);
237  }
238  } else if (sleep_time > 0) {
239  // Be sure not to request a sleep_time of 0, as that's
240  // IMMEDIATE and makes chTdSleepS panic.
241  chThdSleepS(sleep_time);
242  }
243 
244  chSysUnlock();
245 }
246 
247 bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime, const uint32_t increment_ms)
248 {
249  /* TODO: make PIOS_Thread_Systime return opaque type to avoid ms conversion */
250  return CVT_MS2ST(increment_ms) <= chTimeElapsedSince(CVT_MS2ST(prev_systime));
251 }
252 
261 uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
262 {
263 #if CH_DBG_FILL_THREADS
264  uint32_t *stack = (uint32_t*)((size_t)threadp->threadp + sizeof(*threadp->threadp));
265  uint32_t *stklimit = stack;
266  while (*stack ==
267  ((CH_STACK_FILL_VALUE << 24) |
268  (CH_STACK_FILL_VALUE << 16) |
269  (CH_STACK_FILL_VALUE << 8) |
270  (CH_STACK_FILL_VALUE << 0)))
271  ++stack;
272  return (stack - stklimit) * 4;
273 #else
274  return 0;
275 #endif /* CH_DBG_FILL_THREADS */
276 }
277 
287  uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
288 {
289  chSysLock();
290 
291  uint32_t result = threadp->threadp->ticks_total;
292  threadp->threadp->ticks_total = 0;
293 
294  chSysUnlock();
295 
296  return result;
297 }
298 
305 {
306  chSysLock();
307 }
308 
315 {
316  chSysUnlock();
317 }
318 
319 #endif /* defined(PIOS_INCLUDE_CHIBIOS) */
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
Main PiOS header to include all the compiled in PiOS options.
void PIOS_Thread_Scheduler_Suspend(void)
#define PIOS_THREAD_TIMEOUT_MAX
Definition: pios_thread.h:29
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
#define CH_FREQUENCY
System tick frequency.
Definition: chconf.h:48
void PIOS_Thread_ChangePriority(enum pios_thread_prio_e prio)
Definition: pios_thread.c:78
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime, const uint32_t increment_ms)
Determine if a period has elapsed since a datum.
Definition: pios_thread.c:281
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
void PIOS_free(void *buf)
Definition: pios_heap.c:174
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
Definition: pios_thread.c:271
#define DONT_BUILD_IF(COND, MSG)
Definition: morsel.c:206
pios_thread_prio_e
Definition: pios_thread.h:57
uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
Definition: pios_thread.c:276
void PIOS_Thread_Scheduler_Resume(void)
void PIOS_Thread_Delete(struct pios_thread *threadp)
Definition: pios_thread.c:132
uint8_t pad[62]
Definition: bl_messages.h:155
struct pios_thread * PIOS_Thread_WrapCurrentThread(const char *namep)
Creates a handle for the current thread.
Definition: pios_thread.c:51