mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 17:11:42 +00:00
Merge "Add EcOs RTOS abstraction layer and pthreads implementation"
This commit is contained in:
@@ -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)
|
||||
|
||||
516
cros_ec/chip_stub/ec_os.c
Normal file
516
cros_ec/chip_stub/ec_os.c
Normal file
@@ -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 */
|
||||
}
|
||||
93
cros_ec/chip_stub/ec_os_types.h
Normal file
93
cros_ec/chip_stub/ec_os_types.h
Normal file
@@ -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
|
||||
@@ -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,
|
||||
|
||||
119
cros_ec/include/ec_os.h
Normal file
119
cros_ec/include/ec_os.h
Normal file
@@ -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
|
||||
129
cros_ec/test/ec_os_test.c
Normal file
129
cros_ec/test/ec_os_test.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user