diff options
-rw-r--r-- | cros_ec/Makefile | 15 | ||||
-rw-r--r-- | cros_ec/chip_stub/ec_os.c | 516 | ||||
-rw-r--r-- | cros_ec/chip_stub/ec_os_types.h | 93 | ||||
-rw-r--r-- | cros_ec/include/ec_common.h | 2 | ||||
-rw-r--r-- | cros_ec/include/ec_os.h | 119 | ||||
-rw-r--r-- | cros_ec/test/ec_os_test.c | 129 |
6 files changed, 871 insertions, 3 deletions
diff --git a/cros_ec/Makefile b/cros_ec/Makefile index ff59ee3b50..f34db019c3 100644 --- a/cros_ec/Makefile +++ b/cros_ec/Makefile @@ -6,13 +6,22 @@ LIB_SRCS=\ lib/ec_console.c STUB_SRCS=\ + chip_stub/ec_os.c \ chip_stub/ec_uart.c -all: fakemain +TESTPROGS=fakemain ec_os_test + +CFLAGS=-Wall -I include -I chip_stub -pthread + +all: $(TESTPROGS) clean: - rm -f fakemain + rm -f $(TESTPROGS) + +ec_os_test: test/ec_os_test.c chip_stub/ec_os.c + gcc $(CFLAGS) -o ec_os_test \ + test/ec_os_test.c chip_stub/ec_os.c fakemain: test/fakemain.c $(LIB_SRCS) $(STUB_SRCS) - gcc -Wall -I include -o fakemain test/fakemain.c \ + gcc $(CFLAGS) -o fakemain test/fakemain.c \ $(LIB_SRCS) $(STUB_SRCS) diff --git a/cros_ec/chip_stub/ec_os.c b/cros_ec/chip_stub/ec_os.c new file mode 100644 index 0000000000..1997bf9111 --- /dev/null +++ b/cros_ec/chip_stub/ec_os.c @@ -0,0 +1,516 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Operating system library EC */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "ec_common.h" +#include "ec_os.h" + + +static int os_has_started = 0; +static pthread_mutex_t os_start_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t os_start_cond = PTHREAD_COND_INITIALIZER; + + +/* Waits for OS to start */ +static void WaitForOsStart(void) { + pthread_mutex_lock(&os_start_mutex); + if (!os_has_started) + pthread_cond_wait(&os_start_cond, &os_start_mutex); + pthread_mutex_unlock(&os_start_mutex); +} + +static void UsecToTimespec(int usec, struct timespec* ts) { + ts->tv_sec = usec / 1000000; + ts->tv_nsec = 1000 * (long)(usec % 1000000); +} + +/*****************************************************************************/ +/* Tasks */ + +/* Internal data for a task */ +typedef struct EcTaskInternal { + pthread_t thread; + void (*task_func)(void*); + void* param; + struct EcTaskInternal* next; +} EcTaskInternal; + + +static EcTaskInternal* task_list = NULL; +static pthread_mutex_t task_list_mutex = PTHREAD_MUTEX_INITIALIZER; + + +/* Task wrapper. Waits for OS to start, then runs the task function. */ +static void* EcTaskWrapper(void* param) { + EcTaskInternal* ti = (EcTaskInternal*)param; + + WaitForOsStart(); + + /* Chain to the task function */ + ti->task_func(ti->param); + + return NULL; +} + + +EcError EcTaskCreate(EcTask* task, int priority, int stack_size, + void (*task_func)(void*), void* param) { + EcTaskInternal* ti = (EcTaskInternal*)task; + pthread_attr_t attr; + + /* TODO: priority */ + + /* Initialize task data */ + ti->task_func = task_func; + ti->param = param; + + /* Add it to the task list */ + pthread_mutex_lock(&task_list_mutex); + ti->next = task_list; + task_list = ti; + pthread_mutex_unlock(&task_list_mutex); + + /* Mark thread as joinable */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* Create the thread */ + if (pthread_create(&ti->thread, &attr, EcTaskWrapper, ti) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + + +void EcTaskSleep(int usec) { + usleep(usec); +} + + +void EcTaskExit(void) { + pthread_exit(NULL); +} + + +/*****************************************************************************/ +/* Software interrupts (SWI) + * + * SWIs don't exist in pthreads. Simulate them with a thread which waits + * on a semaphore and calls the SWI function when it wakes. */ + +typedef struct EcSwiInternal { + pthread_t thread; + pthread_cond_t cond; + pthread_mutex_t mutex; + uint32_t pending_bits; + void (*swi_func)(void *, uint32_t); + void* param; +} EcSwiInternal; + + +/* SWI wrapper. Loops and calls SWI function when semaphore is signalled. */ +static void* EcSwiWrapper(void* param) { + EcSwiInternal* si = (EcSwiInternal*)param; + + WaitForOsStart(); + + while (1) { + int bits; + + pthread_mutex_lock(&si->mutex); + pthread_cond_wait(&si->cond, &si->mutex); + bits = si->pending_bits; + si->pending_bits = 0; + pthread_mutex_unlock(&si->mutex); + + if (bits) + si->swi_func(si->param, bits); + } + + return NULL; +} + + +EcError EcSwiCreate(EcSwi* swi, int priority, + void (*swi_func)(void*, uint32_t), void* param) { + EcSwiInternal* si = (EcSwiInternal*)swi; + + /* TODO: priority */ + + /* Init internal data */ + si->pending_bits = 0; + si->swi_func = swi_func; + si->param = param; + + /* Allocate pthreads objects for the swi */ + if (pthread_mutex_init(&si->mutex, NULL) != 0) + return EC_ERROR_UNKNOWN; + if (pthread_cond_init(&si->cond, NULL) != 0) + return EC_ERROR_UNKNOWN; + if (pthread_create(&si->thread, NULL, EcSwiWrapper, si) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + + +/* Sets the specified bits in the SWI. */ +EcError EcSwiPost(EcSwi* swi, uint32_t bits) { + EcSwiInternal* si = (EcSwiInternal*)swi; + int prev_bits; + + pthread_mutex_lock(&si->mutex); + + prev_bits = si->pending_bits; + si->pending_bits |= bits; + + if (!prev_bits) + pthread_cond_signal(&si->cond); + + pthread_mutex_unlock(&si->mutex); + + return EC_SUCCESS; +} + + +/*****************************************************************************/ +/* Timers */ + + +typedef struct EcTimerInternal { + pthread_t thread; + pthread_cond_t cond; + pthread_mutex_t mutex; + int interval_usec; + int flags; + void (*timer_func)(void *); + void* param; +} EcTimerInternal; + +/* Timer flags */ +/* Timer is periodic; if not present, timer is one-shot. */ +#define EC_TIMER_FLAG_PERIODIC 0x01 +#define EC_TIMER_FLAG_STARTED 0x02 + + +/* Timer wrapper. Loops and calls timer function. */ +static void* EcTimerWrapper(void* param) { + EcTimerInternal* ti = (EcTimerInternal*)param; + + WaitForOsStart(); + + while (1) { + + /* Wait for timer to be enabled */ + pthread_mutex_lock(&ti->mutex); + if (!(ti->flags & EC_TIMER_FLAG_STARTED)) + pthread_cond_wait(&ti->cond, &ti->mutex); + pthread_mutex_unlock(&ti->mutex); + + /* TODO: should really sleep for interval, less the time used by + * the previous call. Or we could use a second thread to + * pthread_cond_signal() and then immediately go back to sleep. */ + usleep(ti->interval_usec); + + /* Only call the timer func if the flag is still started */ + if (ti->flags & EC_TIMER_FLAG_STARTED) + ti->timer_func(ti->param); + + if (!(ti->flags & EC_TIMER_FLAG_PERIODIC)) + break; /* One-shot timer */ + } + + return NULL; +} + + +/* Creates a timer which will call timer_func(param) after the + * specified interval. See EC_TIMER_FLAG_* for valid flags. Fills + * <timer>. */ +EcError EcTimerCreate(EcTimer* timer, int interval_usec, int priority, + uint32_t flags, void (*timer_func)(void*), void* param) { + EcTimerInternal* ti = (EcTimerInternal*)timer; + + /* TODO: priority */ + + /* Init internal data */ + ti->interval_usec = interval_usec; + ti->flags = flags; + ti->timer_func = timer_func; + ti->param = param; + + /* Create thread to call timer func */ + if (pthread_mutex_init(&ti->mutex, NULL) != 0) + return EC_ERROR_UNKNOWN; + if (pthread_cond_init(&ti->cond, NULL) != 0) + return EC_ERROR_UNKNOWN; + if (pthread_create(&ti->thread, NULL, EcTimerWrapper, ti) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + + +/* Stops a timer. */ +EcError EcTimerStop(EcTimer* timer) { + EcTimerInternal* ti = (EcTimerInternal*)timer; + + pthread_mutex_lock(&ti->mutex); + ti->flags &= ~EC_TIMER_FLAG_STARTED; + pthread_mutex_unlock(&ti->mutex); + return EC_SUCCESS; +} + + +/* Starts a timer. */ +EcError EcTimerStart(EcTimer* timer) { + EcTimerInternal* ti = (EcTimerInternal*)timer; + + pthread_mutex_lock(&ti->mutex); + ti->flags |= EC_TIMER_FLAG_STARTED; + pthread_cond_signal(&ti->cond); + pthread_mutex_unlock(&ti->mutex); + return EC_SUCCESS; +} + + +/*****************************************************************************/ +/* Semaphores */ + +typedef struct EcSemaphoreInternal { + sem_t sem; +} EcSemaphoreInternal; + + +EcError EcSemaphoreCreate(EcSemaphore* semaphore, int initial_count) { + EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore; + + if (sem_init(&si->sem, 0, initial_count) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + + +EcError EcSemaphorePost(EcSemaphore* semaphore) { + EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore; + + if (sem_post(&si->sem) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + + +EcError EcSemaphoreWait(EcSemaphore* semaphore, int timeout_usec) { + EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore; + int rv; + + if (timeout_usec == 0) { + rv = sem_trywait(&si->sem); + + } else if (timeout_usec == EC_OS_FOREVER) { + rv = sem_wait(&si->sem); + if (errno == EAGAIN) + return EC_ERROR_TIMEOUT; + + } else { + struct timespec ts; + UsecToTimespec(timeout_usec, &ts); + rv = sem_timedwait(&si->sem, &ts); + if (errno == ETIMEDOUT) + return EC_ERROR_TIMEOUT; + } + + return (rv == 0 ? EC_SUCCESS : EC_ERROR_UNKNOWN); +} + + +EcError EcSemaphoreGetCount(EcSemaphore* semaphore, int* count_ptr) { + EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore; + + if (sem_getvalue(&si->sem, count_ptr) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + +/*****************************************************************************/ +/* Events */ + +typedef struct EcEventInternal { + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t bits_set; + uint32_t bits_or; + uint32_t bits_and; +} EcEventInternal; + +EcError EcEventCreate(EcEvent* event, uint32_t initial_bits) { + EcEventInternal* ei = (EcEventInternal*)event; + + /* Init internal data */ + ei->bits_set = initial_bits; + ei->bits_or = ei->bits_and = 0; + if (pthread_mutex_init(&ei->mutex, NULL) != 0) + return EC_ERROR_UNKNOWN; + if (pthread_cond_init(&ei->cond, NULL) != 0) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + +/* Turns on the specified bits in the event. */ +EcError EcEventPost(EcEvent* event, uint32_t bits) { + EcEventInternal* ei = (EcEventInternal*)event; + + pthread_mutex_lock(&ei->mutex); + + ei->bits_set |= bits; + + /* See if that's enough bits to release the thread waiting on us */ + if (ei->bits_or & ei->bits_set) { + ei->bits_or = 0; + pthread_cond_signal(&ei->cond); + + } else if (ei->bits_and && (ei->bits_and & ei->bits_set) == ei->bits_and) { + ei->bits_and = 0; + pthread_cond_signal(&ei->cond); + } + + pthread_mutex_unlock(&ei->mutex); + return EC_SUCCESS; +} + + +EcError EcEventWaitAll(EcEvent* event, uint32_t bits, int timeout_usec) { + EcEventInternal* ei = (EcEventInternal*)event; + int rv; + + pthread_mutex_lock(&ei->mutex); + + /* Only wait if we don't have the bits we need */ + if ((ei->bits_set & bits) != bits) { + ei->bits_and = bits; + + if (timeout_usec == EC_OS_FOREVER) { + rv = pthread_cond_wait(&ei->cond, &ei->mutex); + } else { + struct timespec ts; + UsecToTimespec(timeout_usec, &ts); + rv = pthread_cond_timedwait(&ei->cond, &ei->mutex, &ts); + } + } + + /* If we succeeded, consume all the bits we waited for */ + if (!rv) + ei->bits_set &= ~bits; + + pthread_mutex_unlock(&ei->mutex); + + if (rv == ETIMEDOUT) + return EC_ERROR_TIMEOUT; + else + return (rv == 0 ? EC_SUCCESS : EC_ERROR_UNKNOWN); +} + + +EcError EcEventWaitAny(EcEvent* event, uint32_t bits, uint32_t* got_bits_ptr, + int timeout_usec) { + EcEventInternal* ei = (EcEventInternal*)event; + int rv; + + pthread_mutex_lock(&ei->mutex); + + /* Only wait if we don't have the bits we need */ + if (!(ei->bits_set & bits)) { + ei->bits_or = bits; + + if (timeout_usec == EC_OS_FOREVER) { + rv = pthread_cond_wait(&ei->cond, &ei->mutex); + } else { + struct timespec ts; + UsecToTimespec(timeout_usec, &ts); + rv = pthread_cond_timedwait(&ei->cond, &ei->mutex, &ts); + } + } + + /* If we succeeded, consume all the bits we waited for */ + if (!rv) { + if (got_bits_ptr) + *got_bits_ptr = ei->bits_set & bits; + ei->bits_set &= ~bits; + } + + pthread_mutex_unlock(&ei->mutex); + + if (rv == ETIMEDOUT) + return EC_ERROR_TIMEOUT; + else + return (rv == 0 ? EC_SUCCESS : EC_ERROR_UNKNOWN); +} + +/*****************************************************************************/ +/* Other functions */ + + +void EcOsInit(void) { + + /* Make sure struct sizes are correct */ + //printf("%ld", sizeof(EcTimerInternal)); + assert(EC_TASK_STRUCT_SIZE == sizeof(EcTaskInternal)); + assert(EC_SWI_STRUCT_SIZE == sizeof(EcSwiInternal)); + assert(EC_TIMER_STRUCT_SIZE == sizeof(EcTimerInternal)); + assert(EC_SEMAPHORE_STRUCT_SIZE == sizeof(EcSemaphoreInternal)); + assert(EC_EVENT_STRUCT_SIZE == sizeof(EcEventInternal)); +} + + +void EcOsStart(void) { + EcTaskInternal* ti; + + /* Kick off threads */ + pthread_mutex_lock(&os_start_mutex); + os_has_started = 1; + pthread_cond_broadcast(&os_start_cond); + pthread_mutex_unlock(&os_start_mutex); + + /* Wait for all task threads to run */ + while (1) { + EcTaskInternal* ti_wait; + + /* Find the next task */ + pthread_mutex_lock(&task_list_mutex); + ti_wait = task_list; + pthread_mutex_unlock(&task_list_mutex); + if (!ti_wait) + break; /* No tasks left */ + + /* Wait for it to die */ + pthread_join(ti_wait->thread, NULL); + + /* Remove the dead thread from the list */ + pthread_mutex_lock(&task_list_mutex); + if (task_list == ti_wait) + task_list = ti_wait->next; + else { + for (ti = task_list; ti->next == ti_wait; ti = ti->next); + if (ti) + ti->next = ti_wait->next; + } + pthread_mutex_unlock(&task_list_mutex); + } + + /* The remaining tasks for SWIs, etc, will die when the process exits */ +} diff --git a/cros_ec/chip_stub/ec_os_types.h b/cros_ec/chip_stub/ec_os_types.h new file mode 100644 index 0000000000..f9c4a263e0 --- /dev/null +++ b/cros_ec/chip_stub/ec_os_types.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Operating system object types for EC. These are + * implementation-dependent; this file should come from the + * implementation include directory. */ + +#ifndef __CROS_EC_OS_TYPES_H +#define __CROS_EC_OS_TYPES_H + +#include "ec_common.h" + +/* Structure sizes depend on the underlying implementation. These + * sizes are correct for the pthreads implementation. */ +#define EC_TASK_STRUCT_SIZE 32 +#define EC_SWI_STRUCT_SIZE 120 +#define EC_TIMER_STRUCT_SIZE 120 +#define EC_SEMAPHORE_STRUCT_SIZE 32 +#define EC_EVENT_STRUCT_SIZE 104 + +/*****************************************************************************/ +/* Tasks */ + +/* Task priority range */ +#define EC_TASK_PRIORITY_LOWEST 0 +#define EC_TASK_PRIORITY_DEFAULT 3 +#define EC_TASK_PRIORITY_HIGHEST 7 + +/* Task instance. Treat this as an opaque identifier. */ +typedef struct EcTask { + union { + uint64_t align; /* Align on something big */ + uint8_t data[EC_TASK_STRUCT_SIZE]; + }; +} EcTask; + +/*****************************************************************************/ +/* Software interrupts (SWI) */ + +/* SWI priority range */ +#define EC_SWI_PRIORITY_LOWEST 0 +#define EC_SWI_PRIORITY_DEFAULT 3 +#define EC_SWI_PRIORITY_HIGHEST 7 + +/* SWI instance. Treat this as an opaque identifier. */ +typedef struct EcSwi { + union { + uint64_t align; /* Align on something big */ + uint8_t data[EC_SWI_STRUCT_SIZE]; + }; +} EcSwi; + +/*****************************************************************************/ +/* Timers */ + +/* Timer priority range */ +#define EC_TIMER_PRIORITY_LOWEST 0 +#define EC_TIMER_PRIORITY_DEFAULT 3 +#define EC_TIMER_PRIORITY_HIGHEST 7 + +/* Timer instance. Treat this as an opaque identifier. */ +typedef struct EcTimer { + union { + uint64_t align; /* Align on something big */ + uint8_t data[EC_TIMER_STRUCT_SIZE]; + }; +} EcTimer; + +/*****************************************************************************/ +/* Semaphores */ + +/* Semaphore instance. Treat this as an opaque identifier. */ +typedef struct EcSemaphore { + union { + uint64_t align; /* Align on something big */ + uint8_t data[EC_SEMAPHORE_STRUCT_SIZE]; + }; +} EcSemaphore; + +/*****************************************************************************/ +/* Events */ + +/* Event instance. Treat this as an opaque identifier. */ +typedef struct EcEvent { + union { + uint64_t align; /* Align on something big */ + uint8_t data[EC_EVENT_STRUCT_SIZE]; + }; +} EcEvent; + +#endif diff --git a/cros_ec/include/ec_common.h b/cros_ec/include/ec_common.h index 615a88adcf..d5adb4e280 100644 --- a/cros_ec/include/ec_common.h +++ b/cros_ec/include/ec_common.h @@ -25,6 +25,8 @@ enum EcErrorList { EC_ERROR_UNIMPLEMENTED = 2, /* Overflow error; too much input provided. */ EC_ERROR_OVERFLOW = 3, + /* Timeout */ + EC_ERROR_TIMEOUT = 4, /* Module-internal error codes may use this range. */ EC_ERROR_INTERNAL_FIRST = 0x10000, diff --git a/cros_ec/include/ec_os.h b/cros_ec/include/ec_os.h new file mode 100644 index 0000000000..b21e4772cd --- /dev/null +++ b/cros_ec/include/ec_os.h @@ -0,0 +1,119 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Operating system objects for EC */ + +#ifndef __CROS_EC_OS_H +#define __CROS_EC_OS_H + +#include "ec_common.h" +#include "ec_os_types.h" + +/* Timeout value which means "wait forever". */ +#define EC_OS_FOREVER -1 + +/*****************************************************************************/ +/* Tasks */ + +/* Creates a task of the specified priority and stack size. If + * stack_size=0, uses the default stack size. The task will call + * task_func(param). Fills <task>. */ +EcError EcTaskCreate(EcTask* task, int priority, int stack_size, + void (*task_func)(void*), void* param); + +/* Sleep for the specified number of microseconds. */ +void EcTaskSleep(int usec); + +/* Exits the current task. */ +void EcTaskExit(void); + +/*****************************************************************************/ +/* Software interrupts (SWI) */ + +/* Creates a SWI of the specified priority. When the SWI is + * triggered, it will call swi_func(param, bits), where <bits> is the + * accumulated bits value from all preceding calls to EcSwiPost(). + * Fills <swi>. */ +EcError EcSwiCreate(EcSwi* swi, int priority, + void (*swi_func)(void*, uint32_t), void* param); + +/* Sets the specified bits in the SWI. */ +EcError EcSwiPost(EcSwi* swi, uint32_t bits); + +/*****************************************************************************/ +/* Timers */ + +/* Timer flags */ +/* Timer is periodic; if not present, timer is one-shot. */ +#define EC_TIMER_FLAG_PERIODIC 0x01 +#define EC_TIMER_FLAG_STARTED 0x02 + +/* Creates a timer which will call timer_func(param) after the + * specified interval. See EC_TIMER_FLAG_* for valid flags. Fills + * <timer>. */ +EcError EcTimerCreate(EcTimer* timer, int interval_usec, int priority, + uint32_t flags, void (*timer_func)(void*), void* param); + +/* Stops a timer. */ +EcError EcTimerStop(EcTimer* timer); + +/* Starts a timer. */ +EcError EcTimerStart(EcTimer* timer); + +/*****************************************************************************/ +/* Semaphores */ + +/* Creates a semaphore with the specified initial count. Fills <semaphore>. */ +EcError EcSemaphoreCreate(EcSemaphore* semaphore, int initial_count); + +/* Posts the semaphore, incrementing its count by one. If count>0, + * this will allow the next task pending on the semaphore to run. */ +EcError EcSemaphorePost(EcSemaphore* semaphore); + +/* Waits up to <timeout_usec> microseconds (or forever, if + * timeout_usec==EC_OS_FOREVER) for the semaphore. If it's unable to + * acquire the semaphore before the timeout, returns + * EC_ERROR_TIMEOUT. */ +EcError EcSemaphoreWait(EcSemaphore* semaphore, int timeout_usec); + +/* Stores the current semaphore count into <count_ptr>. */ +EcError EcSemaphoreGetCount(EcSemaphore* semaphore, int* count_ptr); + +/*****************************************************************************/ +/* Events + * + * To be compatible with all platforms, only one task at a time may + * wait on an event. */ + +/* Creates an event with the specified initial bits. Fills <event>. */ +EcError EcEventCreate(EcEvent* event, uint32_t initial_bits); + +/* Turns on the specified bits in the event. */ +EcError EcEventPost(EcEvent* event, uint32_t bits); + +/* Waits up to <timeout_usec> microseconds (or forever, if + * timeout_usec==EC_OS_FOREVER) for all of the requested bits to be + * set in the event. Returns EC_ERROR_TIMEOUT on timeout. */ +EcError EcEventWaitAll(EcEvent* event, uint32_t bits, int timeout_usec); + +/* Waits up to <timeout_usec> microseconds (or forever, if + * timeout_usec==EC_OS_FOREVER) for any of the requested bits to be + * set in the event. If got_bits_ptr!=NULL, sets it to the bits which + * were posted, and clears those bits. Returns EC_ERROR_TIMEOUT on timeout. */ +EcError EcEventWaitAny(EcEvent* event, uint32_t bits, uint32_t* got_bits_ptr, + int timeout_usec); + +/*****************************************************************************/ +/* Other OS functions */ + +/* Initializes the OS. Must be called before any of the functions above. */ +void EcOsInit(void); + +/* Starts OS task management. Returns when all threads have exited. + * This function should be called by main(). */ +void EcOsStart(void); + + +#endif diff --git a/cros_ec/test/ec_os_test.c b/cros_ec/test/ec_os_test.c new file mode 100644 index 0000000000..f34ccec4d3 --- /dev/null +++ b/cros_ec/test/ec_os_test.c @@ -0,0 +1,129 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Basic test for EcOs objects */ + +#include <stdio.h> +#include <stdint.h> + +#include "ec_os.h" + +EcTask t1, t2, t3, t4; +EcSemaphore sem; +EcSwi swi; +EcTimer timer1, timer2; +EcEvent ev1, ev2; + + +void Thread1(void* arg) { + int i; + + for (i = 0; i < 5; i++) { + EcSemaphoreWait(&sem, EC_OS_FOREVER); + /* Do some work */ + EcTaskSleep(5000); + fprintf(stderr, "Hello from thread1: %s\n", (char*)arg); + EcSemaphorePost(&sem); + + /* Two rapid posts to SWI, to see that they merge */ + EcSwiPost(&swi, 1 << i); + EcSwiPost(&swi, 0x100 << i); + + EcTaskSleep(100); + } + + EcTaskSleep(500000); + fprintf(stderr, "Goodbye from thread1\n"); +} + + +void Thread2(void* arg) { + int i; + + for (i = 0; i < 5; i++) { + EcSemaphoreWait(&sem, EC_OS_FOREVER); + /* Do some work */ + EcTaskSleep(5000); + fprintf(stderr, "Hello from thread2: %s\n", (char*)arg); + EcSemaphorePost(&sem); + + /* Post events */ + EcEventPost(&ev1, 1 << i); + EcEventPost(&ev2, 1 << i); + + EcTaskSleep(100); + } + + EcTaskSleep(50000); + fprintf(stderr, "Goodbye from thread2\n"); +} + + +void Thread3(void* arg) { + uint32_t got_bits = 0; + + while(got_bits != 0x10) { + /* Wait for any of the bits to be set */ + + EcEventWaitAny(&ev1, 0x1c, &got_bits, EC_OS_FOREVER); + fprintf(stderr, "Event thread 3 got bits: 0x%x\n", got_bits); + } + fprintf(stderr, "Goodbye from event thread 3\n"); +} + + +void Thread4(void* arg) { + /* Wait on event bit from creation and a few posted bits. */ + EcEventWaitAll(&ev2, 0x10e, EC_OS_FOREVER); + fprintf(stderr, "Event thread 4 got all bits\n"); + fprintf(stderr, "Goodbye from event thread 4\n"); +} + + +void SwiFunc(void* arg, uint32_t bits) { + fprintf(stderr, "Hello from SWI with bits=0x%x\n", bits); +} + + +void TimerFunc(void* arg) { + fprintf(stderr, "Hello from timer: %s\n", (char*)arg); + /* Start the one-shot timer. */ + EcTimerStart(&timer2); +} + + +void OneTimerFunc(void* arg) { + fprintf(stderr, "Hello from one-shot timer: %s\n", (char*)arg); + /* Stop the periodic timer */ + EcTimerStop(&timer1); +} + + +int main(void) { + fprintf(stderr, "Hello, world.\n"); + + EcOsInit(); + + EcTaskCreate(&t1, EC_TASK_PRIORITY_DEFAULT, 0, Thread1, "Foo1"); + EcTaskCreate(&t2, EC_TASK_PRIORITY_DEFAULT, 0, Thread2, "Foo2"); + EcTaskCreate(&t3, EC_TASK_PRIORITY_DEFAULT, 0, Thread3, "EventTask1"); + EcTaskCreate(&t4, EC_TASK_PRIORITY_DEFAULT, 0, Thread4, "EventTask2"); + + EcSwiCreate(&swi, EC_SWI_PRIORITY_DEFAULT, SwiFunc, "Swi1"); + EcTimerCreate(&timer1, 100000, EC_TIMER_PRIORITY_DEFAULT, + EC_TIMER_FLAG_STARTED|EC_TIMER_FLAG_PERIODIC, + TimerFunc, "Timer1"); + EcTimerCreate(&timer2, 150000, EC_TIMER_PRIORITY_DEFAULT, + 0, OneTimerFunc, "Timer2"); + EcSemaphoreCreate(&sem, 1); + EcEventCreate(&ev1, 0); + EcEventCreate(&ev2, 0x100); + + fprintf(stderr, "EcOs objects created.\n"); + + EcOsStart(); + + return 0; +} |