diff options
Diffstat (limited to 'src/gos/gos_arduino.c')
| -rw-r--r-- | src/gos/gos_arduino.c | 492 | 
1 files changed, 13 insertions, 479 deletions
| diff --git a/src/gos/gos_arduino.c b/src/gos/gos_arduino.c index 380d528a..c565abb9 100644 --- a/src/gos/gos_arduino.c +++ b/src/gos/gos_arduino.c @@ -11,7 +11,8 @@  #include <string.h>				// Prototype for memcpy() -static void _gosThreadsInit(void); +void _gosHeapInit(void); +void _gosThreadsInit(void);  /*********************************************************   * Initialise @@ -23,7 +24,12 @@ void _gosInit(void)  	 * On the other hand the C runtime should still already be initialized before  	 * getting here!  	 */ -	#warning "GOS: Arduino - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!" +	#if !GFX_OS_INIT_NO_WARNING +		#warning "GOS: Arduino - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!" +	#endif + +	// Start the heap allocator +	_gosHeapInit();  	// Start the scheduler  	_gosThreadsInit(); @@ -53,488 +59,16 @@ void gfxExit(void) {  		dummy++;  } -/********************************************************* - * Head allocation functions - *********************************************************/ - -#include <stdlib.h>				// Prototype for malloc(), realloc() and free() - -void *gfxAlloc(size_t sz) { -	return malloc(sz); -} - -void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) { -	(void) oldsz; -	return realloc(ptr, newsz); -} - -void gfxFree(void *ptr) { -	free(ptr); -} - -/********************************************************* - * Semaphores and critical region functions - *********************************************************/ - -#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON) -	#define INTERRUPTS_OFF() -	#define INTERRUPTS_ON() -#endif - -void gfxSystemLock(void) { -	INTERRUPTS_OFF(); -} - -void gfxSystemUnlock(void) { -	INTERRUPTS_ON(); -} - -void gfxMutexInit(gfxMutex *pmutex) { -	pmutex[0] = 0; -} - -void gfxMutexEnter(gfxMutex *pmutex) { -	INTERRUPTS_OFF(); -	while (pmutex[0]) { -		INTERRUPTS_ON(); -		gfxYield(); -		INTERRUPTS_OFF(); -	} -	pmutex[0] = 1; -	INTERRUPTS_ON(); -} - -void gfxMutexExit(gfxMutex *pmutex) { -	pmutex[0] = 0; -} - -void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) { -	psem->cnt = val; -	psem->limit = limit; -} - -bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) { -	systemticks_t	starttm, delay; - -	// Convert our delay to ticks -	switch (ms) { -	case TIME_IMMEDIATE: -		delay = TIME_IMMEDIATE; -		break; -	case TIME_INFINITE: -		delay = TIME_INFINITE; -		break; -	default: -		delay = gfxMillisecondsToTicks(ms); -		if (!delay) delay = 1; -		starttm = gfxSystemTicks(); -	} - -	INTERRUPTS_OFF(); -	while (psem->cnt <= 0) { -		INTERRUPTS_ON(); -		// Check if we have exceeded the defined delay -		switch (delay) { -		case TIME_IMMEDIATE: -			return FALSE; -		case TIME_INFINITE: -			break; -		default: -			if (gfxSystemTicks() - starttm >= delay) -				return FALSE; -			break; -		} -		gfxYield(); -		INTERRUPTS_OFF(); -	} -	psem->cnt--; -	INTERRUPTS_ON(); -	return TRUE; -} - -bool_t gfxSemWaitI(gfxSem *psem) { -	if (psem->cnt <= 0) -		return FALSE; -	psem->cnt--; -	return TRUE; -} - -void gfxSemSignal(gfxSem *psem) { -	INTERRUPTS_OFF(); -	gfxSemSignalI(psem); -	INTERRUPTS_ON(); -} - -void gfxSemSignalI(gfxSem *psem) { -	if (psem->cnt < psem->limit) -		psem->cnt++; -}  /*********************************************************   * Sleep functions   *********************************************************/ -void gfxSleepMilliseconds(delaytime_t ms) { -	systemticks_t	starttm, delay; - -	// Safety first -	switch (ms) { -	case TIME_IMMEDIATE: -		return; -	case TIME_INFINITE: -		while(1) -			gfxYield(); -		return; -	} - -	// Convert our delay to ticks -	delay = gfxMillisecondsToTicks(ms); -	starttm = gfxSystemTicks(); - -	do { -		gfxYield(); -	} while (gfxSystemTicks() - starttm < delay); +systemticks_t gfxSystemTicks(void) { +	return millis();  } - -void gfxSleepMicroseconds(delaytime_t ms) { -	systemticks_t	starttm, delay; - -	// Safety first -	switch (ms) { -	case TIME_IMMEDIATE: -		return; -	case TIME_INFINITE: -		while(1) -			gfxYield(); -		return; -	} - -	// Convert our delay to ticks -	delay = gfxMillisecondsToTicks(ms/1000); -	starttm = gfxSystemTicks(); - -	do { -		gfxYield(); -	} while (gfxSystemTicks() - starttm < delay); -} - -/********************************************************* - * Threading functions - *********************************************************/ - -/** - * There are some compilers we know how they store the jmpbuf. For those - * we can use the constant macro definitions. For others we have to "auto-detect". - * Auto-detection is hairy and there is no guarantee it will work on all architectures. - * For those it doesn't - read the compiler manuals and the library source code to - * work out the correct macro values. - * You can use the debugger to work out the values for your compiler and put them here. - * Defining these macros as constant values makes the system behavior guaranteed but also - * makes your code compiler and cpu architecture dependent. It also saves a heap of code - * and a few bytes of RAM. - */ -#if GFX_COMPILER == GFX_COMPILER_MINGW32 -	#define AUTO_DETECT_MASK	FALSE -	#define STACK_DIR_UP		FALSE -	#define MASK1				0x00000011 -	#define MASK2				0x00000000 -	#define STACK_BASE			12 -#else -	// Use auto-detection of the stack frame format -	// Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf. -	#define AUTO_DETECT_MASK	TRUE -	#define STACK_DIR_UP		stackdirup			// TRUE if the stack grow up instead of down -	#define MASK1				jmpmask1			// The 1st mask of jmp_buf elements that need relocation -	#define MASK2				jmpmask2			// The 2nd mask of jmp_buf elements that need relocation -	#define STACK_BASE			stackbase			// The base of the stack frame relative to the local variables -	static bool_t		stackdirup; -	static uint32_t		jmpmask1; -	static uint32_t		jmpmask2; -	static size_t		stackbase; -#endif - -#include <setjmp.h> /* jmp_buf, setjmp(), longjmp() */ - -/** - * Some compilers define a _setjmp() and a setjmp(). - * The difference between them is that setjmp() saves the signal masks. - * That is of no use to us so prefer to use the _setjmp() methods. - * If they don't exist compile them to be the standard setjmp() function. - * Similarly for longjmp(). - */ -#if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__) -	#define _setjmp setjmp -#endif -#if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__) -	#define _longjmp longjmp -#endif - -typedef struct thread { -	struct thread *	next;					// Next thread -	int				flags;					// Flags -		#define FLG_THD_ALLOC	0x0001 -		#define FLG_THD_MAIN	0x0002 -		#define FLG_THD_DEAD	0x0004 -		#define FLG_THD_WAIT	0x0008 -	size_t			size;					// Size of the thread stack (including this structure) -	threadreturn_t	(*fn)(void *param);		// Thread function -	void *			param;					// Parameter for the thread function -	jmp_buf			cxt;					// The current thread context. -} thread; - -typedef struct threadQ { -	thread *head; -	thread *tail; -} threadQ; - -static threadQ		readyQ;					// The list of ready threads -static threadQ		deadQ;					// Where we put threads waiting to be deallocated -static thread *		current;				// The current running thread -static thread		mainthread;				// The main thread context - -static void Qinit(threadQ * q) { -	q->head = q->tail = 0; -} - -static void Qadd(threadQ * q, thread *t) { -	t->next = 0; -	if (q->head) { -		q->tail->next = t; -		q->tail = t; -	} else -		q->head = q->tail = t; -} - -static thread *Qpop(threadQ * q) { -	struct thread * t; - -	if (!q->head) -		return 0; -	t = q->head; -	q->head = t->next; -	return t; -} - -#if AUTO_DETECT_MASK -	// The structure for the saved stack frame information -	typedef struct saveloc { -		char *		localptr; -		jmp_buf		cxt; -	} saveloc; - -	// A pointer to our auto-detection buffer. -	static saveloc	*pframeinfo; - -	/* These functions are not static to prevent the compiler removing them as functions */ - -	void get_stack_state(void) { -		char* c; -		pframeinfo->localptr = (char *)&c; -		_setjmp(pframeinfo->cxt); -	} - -	void get_stack_state_in_fn(void) { -		pframeinfo++; -		get_stack_state(); -		pframeinfo--; -	} -#endif - -static void _gosThreadsInit(void) { -	Qinit(&readyQ); -	current = &mainthread; -	current->next = 0; -	current->size = sizeof(thread); -	current->flags = FLG_THD_MAIN; -	current->fn = 0; -	current->param = 0; - -	#if AUTO_DETECT_MASK -		{ -			uint32_t	i; -			char **		pout; -			char **		pin; -			size_t		diff; -			char *		framebase; - -			// Allocate a buffer to store our test data -			pframeinfo = gfxAlloc(sizeof(saveloc)*2); - -			// Get details of the stack frame from within a function -			get_stack_state_in_fn(); - -			// Get details of the stack frame outside the function -			get_stack_state(); - -			/* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */ -			stackdirup =  pframeinfo[1].localptr > pframeinfo[0].localptr; -			pout = (char **)pframeinfo[0].cxt; -			pin =  (char **)pframeinfo[1].cxt; -			diff = pframeinfo[0].localptr - pframeinfo[1].localptr; -			framebase = pframeinfo[0].localptr; -			jmpmask1 = jmpmask2 = 0; -			for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) { -				if ((size_t)(*pout - *pin) == diff) { -					if (i < 32) -						jmpmask1 |= 1 << i; -					else -						jmpmask2 |= 1 << (i-32); - -					if (stackdirup) { -						if (framebase > *pout) -							framebase = *pout; -					} else { -						if (framebase < *pout) -							framebase = *pout; -					} -				} -			} -			stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr); - -			// Clean up -			gfxFree(pframeinfo); -		} -	#endif -} - -gfxThreadHandle gfxThreadMe(void) { -	return (gfxThreadHandle)current; -} - -void gfxYield(void) { -	if (!_setjmp(current->cxt)) { -		// Add us back to the Queue -		Qadd(&readyQ, current); - -		// Check if there are dead processes to deallocate -		while ((current = Qpop(&deadQ))) -			gfxFree(current); - -		// Run the next process -		current = Qpop(&readyQ); -		_longjmp(current->cxt, 1); -	} -} - -// This routine is not currently public - but it could be. -void gfxThreadExit(threadreturn_t ret) { -	// Save the results -	current->param = (void *)ret; -	current->flags |= FLG_THD_DEAD; - -	// Add us to the dead list if we need deallocation as we can't free ourselves. -	// If someone is waiting on the thread they will do the cleanup. -	if ((current->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC) -		Qadd(&deadQ, current); - -	// Switch to the next task -	current = Qpop(&readyQ); -	if (!current) -		gfxExit();		// Oops - this should never happen! -	_longjmp(current->cxt, 1); -} - -gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) { -	thread *	t; -	(void)		prio; - -	// Ensure we have a minimum stack size -	if (stacksz < sizeof(thread)+64) { -		stacksz = sizeof(thread)+64; -		stackarea = 0; -	} - -	if (stackarea) { -		t = (thread *)stackarea; -		t->flags = 0; -	} else { -		t = (thread *)gfxAlloc(stacksz); -		if (!t) -			return 0; -		t->flags = FLG_THD_ALLOC; -	} -	t->size = stacksz; -	t->fn = fn; -	t->param = param; -	if (_setjmp(t->cxt)) { -		// This is the new thread - call the function! -		gfxThreadExit(current->fn(current->param)); - -		// We never get here -		return 0; -	} - -	// Move the stack frame and relocate the context data -	{ -		char **	s; -		char *	nf; -		int		diff; -		uint32_t	i; - -		// Copy the stack frame -		#if AUTO_DETECT_MASK -			if (STACK_DIR_UP) {					// Stack grows up -				nf = (char *)(t) + sizeof(thread) + stackbase; -				memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *)); -			} else {							// Stack grows down -				nf = (char *)(t) + stacksz - (stackbase + sizeof(char *)); -				memcpy(nf, &t, stackbase+sizeof(char *)); -			} -		#elif STACK_DIR_UP -			// Stack grows up -			nf = (char *)(t) + sizeof(thread) + stackbase; -			memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *)); -		#else -			// Stack grows down -			nf = (char *)(t) + size - (stackbase + sizeof(char *)); -			memcpy(nf, &t, stackbase+sizeof(char *)); -		#endif - -		// Relocate the context data -		s = (char **)(t->cxt); -		diff = nf - (char *)&t; - -		// Relocate the elements we know need to be relocated -		for (i = 1; i && i < MASK1; i <<= 1, s++) { -			if ((MASK1 & i)) -				*s += diff; -		} -		#ifdef MASK2 -			for (i = 1; i && i < MASK2; i <<= 1, s++) { -				if ((MASK1 & i)) -					*s += diff; -			} -		#endif -	} - -	// Add this thread to the ready queue -	Qadd(&readyQ, t); -	return t; -} - -threadreturn_t gfxThreadWait(gfxThreadHandle th) { -	thread *		t; - -	t = th; -	if (t == current) -		return -1; - -	// Mark that we are waiting -	t->flags |= FLG_THD_WAIT; - -	// Wait for the thread to die -	while(!(t->flags & FLG_THD_DEAD)) -		gfxYield(); - -	// Unmark -	t->flags &= ~FLG_THD_WAIT; - -	// Clean up resources if needed -	if (t->flags & FLG_THD_ALLOC) -		gfxFree(t); - -	// Return the status left by the dead process -	return (threadreturn_t)t->param; +systemticks_t gfxMillisecondsToTicks(delaytime_t ms) { +	return ms;  } -#endif /* GFX_USE_OS_RAW32 */ +#endif /* GFX_USE_OS_ARDUINO */ | 
