diff --git a/kernel/atom.h b/kernel/atom.h
index 164c968c..08becd2c 100755
--- a/kernel/atom.h
+++ b/kernel/atom.h
@@ -76,6 +76,8 @@ typedef struct atom_tcb
/* Suspension data */
uint8_t suspended; /* TRUE if task is currently suspended */
uint8_t suspend_wake_status; /* Status returned to woken suspend calls */
+ uint32_t suspend_option; /* yujs used for event to save the event flags get option*/
+ uint32_t suspend_info; /* Remember which event flags we are looking for. requested_flags yujs */
ATOM_TIMER *suspend_timo_cb; /* Callback registered for suspension timeouts */
uint8_t terminated; /* TRUE if task is being terminated (run to completion) */
diff --git a/kernel/atomevent.c b/kernel/atomevent.c
new file mode 100755
index 00000000..39a04bb4
--- /dev/null
+++ b/kernel/atomevent.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) 2017, jinsong yu, ramaxel. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. No personal names or organizations' names associated with the
+ * Atomthreads project may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/**
+ * \file
+ * event library.
+ *
+ *
+ * This module implements a event library with the following
+ * features:
+ *
+ * \par Flexible blocking APIs with event
+ * Threads which wish to get a event can choose whether to block,
+ * block with timeout, or not block if the event timeout value is -1.
+ *
+ * \par Interrupt-safe calls
+ * All APIs can be called from interrupt context. Any calls which could
+ * potentially block have optional parameters to prevent blocking if you
+ * wish to call them from interrupt context. Any attempt to make a call
+ * which would block from interrupt context will be automatically and
+ * safely prevented.
+ *
+ * \par Priority-based queueing
+ * Where multiple threads are blocking on a event, they are woken in
+ * order of the threads' priorities. Where multiple threads of the same
+ * priority are blocking, they are woken in FIFO order.
+ *
+ * \par event gruop
+ * event groups range up to a maximum of 32 bit flags.
+ *
+ * \par Smart event deletion
+ * Where a event is deleted while threads are blocking on it, all blocking
+ * threads are woken and returned a status code to indicate the reason for
+ * being woken.
+ *
+ *
+ * \n Usage instructions: \n
+ *
+ * All event objects must be initialised before use by calling
+ * atomEventCreate(). Once initialised atomEventGet() and atomEventGet() are used to
+ * put/get the event respectively.
+ *
+ * If event group is create with all flags cleared, further calls to atomEventGet() will block
+ * the calling thread (unless the calling parameters of timeout request no blocking). If
+ * a call is made to atomEventSet() to satify the requested flags,for the threads are blocking on a zero-count
+ * event flags, the highest priority thread is woken. Where multiple threads of
+ * the same priority are blocking, they are woken in the order in which the
+ * threads started blocking.
+
+ *
+ * Note that those considering using a event group flags are initialised to 0 in
+ * Atomthreads.
+ *
+ */
+
+
+#include "atom.h"
+#include "atomevent.h"
+#include "atomtimer.h"
+
+#include
+
+
+/* Local data types */
+
+typedef struct event_timer
+{
+ ATOM_TCB *tcb_ptr; /* Thread which is suspended with timeout */
+ ATOM_EVENT *event_ptr; /* event the thread is suspended on */
+} EVENT_TIMER;
+
+
+static void atomEventTimerCallback (POINTER cb_data);
+
+/**
+ * \b atomEventCreate
+ *
+ * This function creates a group of 32 event flags. All the flags are
+ * initially in a cleared state.
+ * Must be called before calling any other event library routines on a
+ * event. Objects can be deleted later using atom_event_Delete().
+ *
+ * Does not allocate storage, the caller provides the
+ *
+ * This function can be called from interrupt context.
+ * event_ptr is clear during creation
+ *
+ * @param[in] event_ptr Pointer to event flags group control block
+ * @param[in] Pointer to event flags name
+ *
+ * @retval ATOM_OK Success
+ * @retval ATOM_ERR_PARAM Bad parameters
+ */
+uint8_t atomEventCreate(ATOM_EVENT *event_ptr, char *name_ptr)
+{
+
+ uint8_t status;
+
+ /* Initialize event flags control block to all zeros. */
+ //memset(event_ptr, 0, sizeof(ATOM_EVENT));
+
+ /* Parameter check */
+ if (event_ptr == NULL)
+ {
+ /* Bad event pointer */
+ status = ATOM_ERR_PARAM;
+ }
+ else
+ {
+
+ /* Initialize the suspended threads queue */
+ event_ptr->suspQ = NULL;
+
+ event_ptr->atom_event_current=0;
+
+ /* Successful */
+ status = ATOM_OK;
+ }
+
+ return (status);
+}
+
+
+
+
+/**
+ * \b atomEventGet
+ *
+ * Perform a get operation on a event group flags.
+ *
+ * This check the 32bit event groups flags and returns.
+
+ * Depending on the \c timeout value specified the call will do one of
+ * the following if the count value is zero:
+ * @param[in] timeout
+ * \c timeout == 0 : Call will block until event flag is satisfied or event group is deleted \n
+ * \c timeout > 0 : Call will block until non-zero up to the specified timeout \n
+ * \c timeout == -1 : Return immediately even the event flags requested which is not satified \n
+ **
+ * If the call needs to block and \c timeout is non-zero, the call will only
+ * block for the specified number of system ticks after which time, if the
+ * thread was not already woken, the call will return with \c ATOM_TIMEOUT.
+ *
+ * If the call would normally block and \c timeout is -1, the call will
+ * return immediately with \c ATOM_WOULDBLOCK.
+ *
+ * This function can only be called from interrupt context if the \c timeout
+ * parameter is -1 (in which case it does not block).
+ *
+ * @param[in] event Pointer to event object
+ * @param[in] timeout Max system ticks to block (0 = forever, -1 return immediately)
+ *
+ * @param[in] event_ptr Pointer to group control block
+ * @param[in] requested_flags Event flags requested
+ * @param[in] get_option Specifies the all flags/any flags is satified by AND/OR
+ * @param[in] actual_flags_ptr Pointer to place the actual flags
+ * @param[in] timeout Suspension option
+ *
+
+
+ * @retval ATOM_OK Success
+ * @retval ATOM_TIMEOUT event timed out before being woken
+ * @retval ATOM_WOULDBLOCK Called with timeout == -1 but count is zero
+ * @retval ATOM_ERR_DELETED event was deleted while suspended
+ * @retval ATOM_ERR_CONTEXT Not called in thread context and attempted to block
+ * @retval ATOM_ERR_PARAM Bad parameter
+ * @retval ATOM_ERR_QUEUE Problem putting the thread on the suspend queue
+ * @retval ATOM_ERR_TIMER Problem registering the timeout
+ */
+
+uint8_t atomEventGet(ATOM_EVENT *event_ptr, uint32_t requested_flags,
+ uint8_t get_option, uint32_t *actual_flags_ptr, uint32_t timeout)
+{
+ uint8_t status;
+ EVENT_TIMER timer_data;
+ ATOM_TIMER timer_cb;
+ ATOM_TCB *curr_tcb_ptr;
+
+ uint32_t current_flags;
+#ifdef DEBUG_EVENT
+ printf("%s enter \n",__func__);
+#endif
+ CRITICAL_STORE;
+ /* Check parameters
+ * Check for an invalid destination for actual flags.
+ * Check for invalid get option.
+ * */
+ if (event_ptr == NULL || actual_flags_ptr == NULL || get_option > ATOM_AND_CLEAR)
+ {
+ /* Bad event pointer */
+ return(ATOM_ERR_PARAM);
+ }
+
+ else
+ {
+ /* Protect access to the event object and OS queues */
+ CRITICAL_START ();
+
+ current_flags = event_ptr -> atom_event_current;
+#ifdef DEBUG_EVENT
+ printf("atomEventGet current_flags %d \n",(int)event_ptr -> atom_event_current);
+#endif
+ /* Determine if the event flags are present, based on the get option. */
+ if (get_option & ATOM_EVENT_AND_MASK)
+ {
+
+ /* All flags must be present to satisfy request. */
+ if ((current_flags & requested_flags) == requested_flags)
+ {
+ /* Yes, all the events are present. */
+ status = ATOM_OK;
+ }
+ else
+ {
+
+ /* No, not all the events are present. */
+ status = ATOM_NO_EVENTS;
+ }
+ }
+ else
+ {
+
+ /* Any of the events will satisfy the request. so return immediately or will suspending the thread..*/
+ if (current_flags & requested_flags)
+ {
+
+ /* Yes, one or more of the requested events are set. */
+ status = ATOM_OK;
+ }
+ else
+ {
+
+ /* No, none of the events are currently set. */
+ status = ATOM_NO_EVENTS;
+ }
+ }
+
+ /* Now determine if the request can be satisfied immediately. */
+ if (status == ATOM_OK)
+ {
+
+ /* Yes, this request can be handled immediately. */
+
+ /* Return the actual event flags that satisfied the request. */
+ *actual_flags_ptr = current_flags;
+
+ /* Determine whether or not clearing needs to take place. */
+ if (get_option & ATOM_EVENT_CLEAR_MASK)
+ {
+
+ /* Yes, clear the flags that satisfied this request. */
+ event_ptr -> atom_event_current =
+ event_ptr -> atom_event_current & ~requested_flags;
+ }
+ CRITICAL_END ();/*ensure each exit have chance to end the critical in each case*/
+ }
+ else
+ {
+#ifdef DEBUG_EVENT
+ printf("%s not meet the reqeust flag go here \n",__func__);
+#endif
+ /* Determine if the request specifies suspension. it is timeout value ATOM_WAIT_FOREVER*/
+ if (timeout >=0 )
+ {
+ /* Prepare for suspension of this thread. */
+
+ /* Get the current TCB */
+ curr_tcb_ptr = atomCurrentContext();
+ /* Check we are actually in thread context */
+ if (curr_tcb_ptr)
+ {
+ /* Add current thread to the suspend list on this event */
+ if (tcbEnqueuePriority (&event_ptr->suspQ, curr_tcb_ptr) != ATOM_OK)
+ {
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* There was an error putting this thread on the suspend list */
+ status = ATOM_ERR_QUEUE;
+ }
+ else
+ {
+ /* Set suspended status for the current thread */
+ curr_tcb_ptr->suspended = TRUE;
+ status = ATOM_OK;
+
+ /* Remember which event flags we are looking for. */
+ curr_tcb_ptr -> suspend_info = requested_flags;
+ curr_tcb_ptr -> suspend_option = get_option;
+#ifdef DEBUG_EVENT
+ printf("atomEventGet suspend_option %d \n",(int)curr_tcb_ptr -> suspend_option);
+ printf("atomEventGet suspend_info %d \n",(int)curr_tcb_ptr -> suspend_info);
+#endif
+
+ /* Track errors */
+
+
+ /* Register a timer callback if requested */
+ if (timeout)
+ {
+ /* Fill out the data needed by the callback to wake us up */
+ timer_data.tcb_ptr = curr_tcb_ptr;
+ timer_data.event_ptr = event_ptr;
+
+ /* Fill out the timer callback request structure */
+ timer_cb.cb_func = atomEventTimerCallback;
+ timer_cb.cb_data = (POINTER)&timer_data;
+ timer_cb.cb_ticks = timeout;
+
+ /**
+ * Store the timer details in the TCB so that we can
+ * cancel the timer callback if the event is put
+ * before the timeout occurs.
+ */
+ curr_tcb_ptr->suspend_timo_cb = &timer_cb;
+
+ /* Register a callback on timeout */
+ if (atomTimerRegister (&timer_cb) != ATOM_OK)
+ {
+ /* Timer registration failed */
+ status = ATOM_ERR_TIMER;
+
+ /* Clean up and return to the caller */
+ (void)tcbDequeueEntry (&event_ptr->suspQ, curr_tcb_ptr);
+ curr_tcb_ptr->suspended = FALSE;
+ curr_tcb_ptr->suspend_timo_cb = NULL;
+ }
+ }
+
+ /* Set no timeout requested */
+ else
+ {
+ /* No need to cancel timeouts on this one */
+ curr_tcb_ptr->suspend_timo_cb = NULL;
+ }
+
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* Check no errors have occurred */
+ if (status == ATOM_OK )
+
+ {
+ /**
+ * Current thread now blocking, schedule in a new
+ * one. We already know we are in thread context
+ * so can call the scheduler from here.
+ */
+#ifdef DEBUG_EVENT
+ printf("%s suspend here \n",__func__);
+#endif
+ atomSched (FALSE);
+
+#ifdef DEBUG_EVENT
+ printf("%s suspend go \n",__func__);
+#endif
+
+ /**
+ * Normal atomEventGet() wakeups will set ATOM_OK status,
+ * while timeouts will set ATOM_TIMEOUT and event
+ * deletions will set ATOM_ERR_DELETED.
+ */
+ status = curr_tcb_ptr->suspend_wake_status;
+
+ /**
+ * If we have been woken up with ATOM_OK then
+ * another thread set the event flags and
+ * handed control to this thread.
+ */
+
+ }
+ }
+ }
+ else
+ {
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* Not currently in thread context, can't suspend */
+ status = ATOM_ERR_CONTEXT;
+ }
+ }
+
+ else
+ {
+ /* timeout == -1, requested not to block and count is zero */
+ CRITICAL_END();
+ status = ATOM_WOULDBLOCK;
+ }
+
+ }
+
+ }
+#ifdef DEBUG_EVENT
+ printf("status %d leave \n",(unsigned int)status);
+ printf("%s leave \n",__func__);
+#endif
+
+ /* Return actual completion status. */
+ return(status);
+}
+
+
+/**
+ * \b atomEventTimerCallback
+ *
+ * This is an internal function not for use by application code.
+ *
+ * Timeouts on suspended threads are notified by the timer system through
+ * this generic callback. The timer system calls us back with a pointer to
+ * the relevant \c EVENT_TIMER object which is used to retrieve the
+ * event group flags.
+ *
+ * @param[in] cb_data Pointer to a EVENT_TIMER object
+ */
+static void atomEventTimerCallback (POINTER cb_data)
+{
+ EVENT_TIMER *timer_data_ptr;
+#ifdef DEBUG_EVENT
+ printf("%s enter \n",__func__);
+#endif
+
+ CRITICAL_STORE;
+
+ /* Get the EVENT_TIMER structure pointer */
+ timer_data_ptr = (EVENT_TIMER *)cb_data;
+
+ /* Check parameter is valid */
+ if (timer_data_ptr)
+ {
+ /* Enter critical region */
+ CRITICAL_START ();
+
+ /* Set status to indicate to the waiting thread that it timed out */
+ timer_data_ptr->tcb_ptr->suspend_wake_status = ATOM_TIMEOUT;
+
+ /* Flag as no timeout registered */
+ timer_data_ptr->tcb_ptr->suspend_timo_cb = NULL;
+
+ /* Remove this thread from the event suspend list */
+ (void)tcbDequeueEntry (&timer_data_ptr->event_ptr->suspQ, timer_data_ptr->tcb_ptr);
+
+ /* Put the thread on the ready queue */
+ (void)tcbEnqueuePriority (&tcbReadyQ, timer_data_ptr->tcb_ptr);
+
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /**
+ * Note that we don't call the scheduler now as it will be called
+ * when we exit the ISR by atomIntExit().
+ */
+ }
+#ifdef DEBUG_EVENT
+ printf("%s leave \n",__func__);
+#endif
+
+}
+/* */
+/* DESCRIPTION */
+/* */
+/* This function sets the specified flags in the event group based on */
+/* the set option specified. All threads suspended on the group whose */
+/* get request can now be satisfied are resumed. */
+/* */
+/* INPUT */
+/* */
+/* group_ptr Pointer to group control block */
+/* flags_to_set Event flags to set */
+/* set_option Specified either AND or OR */
+/* operation on the event flags */
+/* */
+/* OUTPUT */
+/* */
+/* TX_SUCCESS Always returns success */
+/* */
+/* CALLS */
+/* */
+/* _tx_thread_system_preempt_check Check for preemption */
+/* _tx_thread_system_resume Resume thread service */
+/* _tx_thread_system_ni_resume Non-interruptable resume thread */
+/* */
+/* CALLED BY */
+
+/**
+ * \b atomEventSet
+ *
+ * This function sets the specified flags in the event group based on
+ * the set option specified. All threads suspended on the group whose
+ * get request can now be satisfied are resumed.
+ * if there are threads blocking on the
+ * event, the call will wake up the highest priority thread suspended. Only
+ * one thread is woken per call to atomEventSet(). If multiple threads of the
+ * same priority are suspended, they are woken in order of suspension (FIFO).
+ *
+ * This function can be called from interrupt context.
+ *
+ * @param[in] event_ptr group Pointer to event object
+ * @param[in] flags_to_set to set
+ * @param[in] set_option which define the OR/AND operation for the requested event flags in atomEventGet
+ *
+ * @retval ATOM_OK Success
+ * @retval ATOM_ERR_PARAM Bad parameter
+ * @retval ATOM_ERR_QUEUE Problem putting a woken thread on the ready queue
+ * @retval ATOM_ERR_TIMER Problem cancelling a timeout for a woken thread
+ */
+uint8_t atomEventSet(ATOM_EVENT *event_ptr, uint32_t flags_to_set, uint8_t set_option)
+{
+
+ uint8_t status;
+ CRITICAL_STORE;
+ ATOM_TCB *tcb_ptr;
+
+#ifdef DEBUG_EVENT
+ printf("%s enter \n",__func__);
+#endif
+ /* Check parameters
+ * Check for an invalid destination for actual flags.
+ * Check for invalid get option.
+ * */
+ if (event_ptr == NULL || ((set_option != ATOM_AND) && (set_option != ATOM_OR)) )
+ {
+ /* Bad event pointer */
+ return(ATOM_ERR_PARAM);
+ }
+
+ else
+ {
+ CRITICAL_START ();
+ /* Determine how to set this group's event flags. */
+ if (set_option & ATOM_EVENT_AND_MASK)
+ {
+
+ /* Previous set operation was not interrupted, simply clear the
+ specified flags by "ANDing" the flags into the current events
+ of the group. */
+ event_ptr -> atom_event_current =
+ event_ptr -> atom_event_current & flags_to_set;
+
+ /* There is no need to check for any suspended threads since no
+ new bits are set. */
+ CRITICAL_END ();
+
+ /* Return successful status. */
+ return(ATOM_OK);
+ }
+ else
+ {
+
+ /* "OR" the flags into the current events of the group. */
+ event_ptr -> atom_event_current =
+ event_ptr -> atom_event_current | flags_to_set;
+
+ /* Determine if there are any delayed flags to clear. */
+ }
+
+
+#ifdef DEBUG_EVENT
+ printf(" event_ptr -> atom_event_current 0x%8x \n",(unsigned int)event_ptr -> atom_event_current);
+#endif
+
+ /* If any threads are blocking on the event, wake up one */
+ if (event_ptr->suspQ)
+ {
+#ifdef DEBUG_EVENT
+ printf("tcbDequeueHead to pull out queue.\n");
+#endif
+
+ tcb_ptr = tcbDequeueHead (&event_ptr->suspQ);
+ ////////////////////////////////////////////////////////
+ /* copy from thread event get.***********/
+ /* Determine if this thread's get event flag request has been met. */
+ if (tcb_ptr -> suspend_option & ATOM_EVENT_AND_MASK)
+ {
+#ifdef DEBUG_EVENT
+ printf("AND event_ptr -> atom_event_current 0x%8x \n",(unsigned int)event_ptr -> atom_event_current);
+ printf("AND event_ptr -> suspend_info 0x%8x \n",(unsigned int)tcb_ptr -> suspend_info);
+#endif
+
+
+ /* All flags must be present to satisfy request. */
+ if ((event_ptr -> atom_event_current & tcb_ptr -> suspend_info) ==
+ tcb_ptr -> suspend_info)
+
+ /* Yes, all the events are present. */
+ status = ATOM_OK;
+ else
+
+ /* No, not all the events are present. */
+ status = ATOM_NO_EVENTS;
+ }
+ else
+ {
+#ifdef DEBUG_EVENT
+ printf("OR event_ptr -> atom_event_current 0x%8x \n",(unsigned int)event_ptr -> atom_event_current);
+ printf("OR event_ptr -> suspend_info 0x%8x \n",(unsigned int)tcb_ptr -> suspend_info);
+#endif
+
+
+ /* Any of the events will satisfy the request. */
+ if (event_ptr -> atom_event_current & tcb_ptr -> suspend_info)
+
+ /* Yes, one or more of the requested events are set. */
+ status = ATOM_OK;
+ else
+
+ /* No, none of the events are currently set. */
+ status = ATOM_NO_EVENTS;
+ }
+#ifdef DEBUG_EVENT
+ printf("check suspQ status %d \n",(unsigned int)status);
+#endif
+
+
+
+ /* Was the suspended thread's event request satisfied? */
+ /* enter this case it must return OK*/
+ if (status == ATOM_OK)
+ {
+
+ /* Yes, resume the thread and apply any event flag
+ clearing. */
+
+ /* Determine whether or not clearing needs to take place. */
+ if (tcb_ptr ->suspend_option & ATOM_EVENT_CLEAR_MASK)
+ {
+
+ /* Yes, clear the flags that satisfied this request. */
+ event_ptr -> atom_event_current =
+ event_ptr -> atom_event_current & ~(tcb_ptr ->suspend_option);
+ }
+
+
+ /* Set OK status to be returned to the waiting thread */
+ tcb_ptr->suspend_wake_status = ATOM_OK;
+
+
+#ifdef DEBUG_EVENT
+ printf ("enqueue the thread into ready queue \n");
+#endif
+ if (tcbEnqueuePriority (&tcbReadyQ, tcb_ptr) != ATOM_OK)
+ {
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* There was a problem putting the thread on the ready queue */
+ status = ATOM_ERR_QUEUE;
+ }
+ else
+ {
+ if ((tcb_ptr->suspend_timo_cb != NULL)
+ && (atomTimerCancel (tcb_ptr->suspend_timo_cb) != ATOM_OK))
+ {
+ /* There was a problem cancelling a timeout on this event */
+ status = ATOM_ERR_TIMER;
+ }
+ else
+ {
+ /* Flag as no timeout registered */
+ tcb_ptr->suspend_timo_cb = NULL;
+
+ /* Successful */
+ status = ATOM_OK;
+ }
+
+
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /**
+ * The scheduler may now make a policy decision to thread
+ * switch if we are currently in thread context. If we are
+ * in interrupt context it will be handled by atomIntExit().
+ */
+ if (atomCurrentContext())
+ atomSched (FALSE);
+ }
+ }
+
+ else/* if not the ATOM_OK, enqueue the ptr checkout just now*/
+ {
+
+ //case for ATOM_NO_EVENTS
+
+#ifdef DEBUG_EVENT
+ printf("status %d \n",status);
+ printf("tcbEnqueuePriority to suspq\n");
+#endif
+ if (tcb_ptr)
+ {
+ if (tcbEnqueuePriority (&event_ptr->suspQ, tcb_ptr) != ATOM_OK)
+ {
+
+ /* There was a problem putting the thread on the ready queue */
+ status = ATOM_ERR_QUEUE;
+ }
+ }
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ }
+
+ /**
+ * Threads are woken up in priority order, with a FIFO system
+ * used on same priority threads. We always take the head,
+ * ordering is taken care of by an ordered list enqueue.
+ */
+
+ }/*end of suspend quque*/
+ else
+ {
+ /* Exit critical region added 0329*/
+ CRITICAL_END ();
+ }
+
+ }/* end of else event_ptr == NULL*/
+
+
+#ifdef DEBUG_EVENT
+ printf("status %d leave \n",(unsigned int)status);
+ printf("%s leave \n",__func__);
+#endif
+ return (status);
+}
+
+
+/* DESCRIPTION */
+/* */
+/* This function deletes the specified event flag group. All threads */
+/* suspended on the group are resumed with the ATOM_DELETED status */
+
+uint8_t atomEventDelete (ATOM_EVENT *event_ptr)
+{
+ uint8_t status;
+ CRITICAL_STORE;
+ ATOM_TCB *tcb_ptr;
+ uint8_t woken_threads = FALSE;
+
+ /* Parameter check */
+ if (event_ptr == NULL)
+ {
+ /* Bad event pointer */
+ status = ATOM_ERR_PARAM;
+ }
+ else
+ {
+ /* Default to success status unless errors occur during wakeup */
+ status = ATOM_OK;
+
+ /* Wake up all suspended tasks */
+ while (1)
+ {
+ /* Enter critical region */
+ CRITICAL_START ();
+
+ /* Check if any threads are suspended */
+ tcb_ptr = tcbDequeueHead (&event_ptr->suspQ);
+
+ /* A thread is suspended on the event group */
+ if (tcb_ptr)
+ {
+#ifdef DEBUG_EVENT
+ printf("tcb_ptr->suspend_wake_status %d\n",tcb_ptr->suspend_wake_status);
+#endif
+
+ /* Return error status to the waiting thread */
+ tcb_ptr->suspend_wake_status = ATOM_ERR_DELETED;
+
+ /* Put the thread on the ready queue */
+ if (tcbEnqueuePriority (&tcbReadyQ, tcb_ptr) != ATOM_OK)
+ {
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* Quit the loop, returning error */
+ status = ATOM_ERR_QUEUE;
+ break;
+ }
+
+ /* If there's a timeout on this suspension, cancel it */
+ if (tcb_ptr->suspend_timo_cb)
+ {
+ /* Cancel the callback */
+ if (atomTimerCancel (tcb_ptr->suspend_timo_cb) != ATOM_OK)
+ {
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* Quit the loop, returning error */
+ status = ATOM_ERR_TIMER;
+ break;
+ }
+
+ /* Flag as no timeout registered */
+ tcb_ptr->suspend_timo_cb = NULL;
+
+ }
+
+ /* Exit critical region */
+ CRITICAL_END ();
+
+ /* Request a reschedule */
+ woken_threads = TRUE;
+ }
+
+ /* No more suspended threads */
+ else
+ {
+ /* Exit critical region and quit the loop */
+ CRITICAL_END ();
+ break;
+ }
+ }
+
+ /* Call scheduler if any threads were woken up */
+ if (woken_threads == TRUE)
+ {
+ /**
+ * Only call the scheduler if we are in thread context, otherwise
+ * it will be called on exiting the ISR by atomIntExit().
+ */
+ if (atomCurrentContext())
+ atomSched (FALSE);
+ }
+ }
+
+ return (status);
+}
+
+
diff --git a/kernel/atomevent.h b/kernel/atomevent.h
new file mode 100755
index 00000000..106ae68d
--- /dev/null
+++ b/kernel/atomevent.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, jinsong yu, ramaxel, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. No personal names or organizations' names associated with the
+ * Atomthreads project may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ATOM_EVENT_H
+#define __ATOM_EVENT_H
+
+
+#define ATOM_NO_WAIT 0
+#define ATOM_WAIT_FOREVER 0xFFFFFFFFUL
+#define ATOM_AND 2
+#define ATOM_AND_CLEAR 3
+#define ATOM_OR 0
+#define ATOM_OR_CLEAR 1
+
+
+
+#define ATOM_EVENT_AND_MASK 0x2
+#define ATOM_EVENT_CLEAR_MASK 0x1
+
+
+
+#define ATOM_NO_EVENTS 0x07 //located it here temp.. place it in atom.h finnally.
+
+/*ATOM_EVENT_FLAGS_GROUP * _ATOM_event_flags_created_ptr;*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Define the event flags group structure utilized by the application. */
+
+typedef struct atom_event
+{
+ uint32_t atom_event_current;
+ ATOM_TCB * suspQ; /* Queue of threads suspended on this event */
+
+} ATOM_EVENT;
+
+
+
+extern uint8_t atomEventCreate(ATOM_EVENT *event_ptr, char *name_ptr);
+extern uint8_t atomEventDelete (ATOM_EVENT *event_ptr);
+extern uint8_t atomEventGet(ATOM_EVENT *event_ptr, uint32_t requested_flags,\
+ uint8_t get_option, uint32_t *actual_flags_ptr, uint32_t timeout);
+extern uint8_t atomEventSet(ATOM_EVENT *event_ptr, uint32_t flags_to_set, uint8_t set_option);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* __ATOM_EVENT_H */
diff --git a/tests/event1.c b/tests/event1.c
new file mode 100755
index 00000000..4bf285be
--- /dev/null
+++ b/tests/event1.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2017, jinsong yu ramaxel. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. No personal names or organizations' names associated with the
+ * Atomthreads project may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "atom.h"
+#include "atomevent.h"
+#include "atomtests.h"
+
+#define RX_COMPLETE_FLAG 0x01
+#define TX_COMPLETE_FLAG 0x02
+
+
+/* Number of test threads */
+#define NUM_TEST_THREADS 2
+
+
+/* Test OS objects */
+static ATOM_EVENT event1, event2;
+static ATOM_TCB tcb[NUM_TEST_THREADS];
+static uint8_t test_thread_stack[NUM_TEST_THREADS][TEST_THREAD_STACK_SIZE];
+
+
+/* Forward declarations */
+static void test1_thread_func (uint32_t param);
+static void test2_thread_func (uint32_t param);
+
+static int event_set_tx_flag();
+//static void settimer2(uint32_t timeout);
+static int event_set_rx_flag();
+//static void settimer1(uint32_t timeout);
+
+
+/**
+ * \b test_start
+ *
+ * Start event get/set test,
+ *
+ * case1: create the thread1,event1,get with option ATOM_AND_CLEAR which means tx/rx here should be satisfied simulatiouly.
+ * here set the tx/rx one by one to see what happens, it expect the thread2 get the flag after the event_set_tx_flag.
+ *
+ * case2: create the thread2,event2,get with option ATOM_AND_CLEAR which means tx/rx here should be satisfied simulatiouly.
+ * here set the tx/rx one by one to see what happens, it expect the thread2 get the flag after the event_set_tx_flag.
+ *
+ * @retval Number of failures
+ */
+uint32_t test_start (void)
+{
+ int failures;
+
+ failures = 0;
+ //case1:
+ ATOMLOG (_STR("test event1 case1: get option ATOM_OR_CLEAR ,set option ATOM_OR \n"));
+
+ if (atomEventCreate (&event1, 0) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Error creating test event 1\n"));
+ failures++;
+ }
+ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0,
+ &test_thread_stack[0][0],
+ TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error creating test thread 1\n"));
+ failures++;
+ }
+ else
+ {
+ /* let thread1 to exec */
+ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC*5) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Failed timer delay\n"));
+ }
+
+ if( event_set_rx_flag() != ATOM_OK )
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error get the thread 1 flag \n"));
+ failures++;
+ }
+
+ atomTimerDelay (150*SYSTEM_TICKS_PER_SEC);
+ printf("thread1 test passed \n");
+ }
+
+
+ //case2:
+ ATOMLOG (_STR("test event2 case2: get option ATOM_AND_CLEAR,set option ATOM_OR \n"));
+
+ if (atomEventCreate (&event2, 0) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Error creating test event 2\n"));
+ failures++;
+ }
+ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0,
+ &test_thread_stack[1][0],
+ TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error creating test thread 2\n"));
+ failures++;
+ }
+ else
+ {
+ /* let thread2 to exec */
+ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC*5) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Failed timer delay\n"));
+ }
+
+ if( event_set_rx_flag() == ATOM_OK )
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error get the thread 2 flag \n"));
+ failures++;
+ }
+
+ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC*10) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Failed timer delay\n"));
+ }
+
+ if( event_set_tx_flag() != ATOM_OK )
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error get the thread 2 flag \n"));
+ failures++;
+ }
+
+ atomTimerDelay (150*SYSTEM_TICKS_PER_SEC);
+ printf("thread2 test passed \n");
+ }
+
+ /* Check thread stack usage (if enabled) */
+#ifdef ATOM_STACK_CHECKING
+ {
+ uint32_t used_bytes, free_bytes;
+ int thread;
+
+ /* Check all threads */
+ for (thread = 0; thread < NUM_TEST_THREADS; thread++)
+ {
+ /* Check thread stack usage */
+ if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
+ {
+ ATOMLOG (_STR("StackCheck\n"));
+ failures++;
+ }
+ else
+ {
+ /* Check the thread did not use up to the end of stack */
+ if (free_bytes == 0)
+ {
+ ATOMLOG (_STR("StackOverflow %d\n"), thread);
+ failures++;
+ }
+
+ /* Log the stack usage */
+#ifdef TESTS_LOG_STACK_USAGE
+ ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
+#endif
+ }
+ }
+ }
+#endif
+
+ /* Quit */
+ return failures;
+}
+
+/**
+ * \b test1_thread_func
+ *
+ * Entry point for test thread 1
+ *
+ * @param[in] param Unused (optional thread entry parameter)
+ *
+ * @return None
+ */
+static void test1_thread_func (uint32_t param)
+{
+ uint8_t status;
+ uint32_t actual_flags_ptr;
+ uint32_t requested_flags;
+ /* Compiler warnings */
+ param = param;
+
+ /*
+ * Wait on event2 get the flag. We are expecting to be woken up
+ * by after the .event_set_tx_flag
+ */
+ requested_flags = (RX_COMPLETE_FLAG | RX_COMPLETE_FLAG);
+ printf("test1_thread_func get requested_flags %d \n",(unsigned int)requested_flags);
+ requested_flags=3;
+
+ status = atomEventGet(&event1, requested_flags,ATOM_OR_CLEAR,&actual_flags_ptr,0xf0000001);//ATOM_WAIT_FOREVER
+
+ printf("test1_thread_func status11 %d\n",status);//can't get also exec to here???
+ if (status != ATOM_OK)
+ {
+ ATOMLOG (_STR("Test1 thread failed to wakeup (%d)\n"), status);
+ }
+
+ /* Wait forever */
+ while (1)
+ {
+ atomTimerDelay (SYSTEM_TICKS_PER_SEC);
+ }
+}
+
+
+/**
+ * \b test2_thread_func
+ *
+ * Entry point for test thread 2.
+ *
+ * @param[in] param Unused (optional thread entry parameter)
+ *
+ * @return None
+ */
+static void test2_thread_func (uint32_t param)
+{
+ uint8_t status;
+ uint32_t actual_flags_ptr;
+ uint32_t requested_flags;
+ /* Compiler warnings */
+ param = param;
+
+ /*
+ * Wait on event2 get the flag. We are expecting to be woken up
+ * by after the .event_set_tx_flag
+ */
+ requested_flags = (RX_COMPLETE_FLAG | RX_COMPLETE_FLAG);
+ printf("test2_thread_func get requested_flags %d \n",(unsigned int)requested_flags);
+ requested_flags=3;
+
+ status = atomEventGet(&event2, requested_flags,ATOM_AND_CLEAR,&actual_flags_ptr,0xf0000001);//ATOM_WAIT_FOREVER
+
+ printf("test2_thread_func status11 %d\n",status);//can't get also exec to here???
+ if (status != ATOM_OK)
+ {
+ ATOMLOG (_STR("Test2 thread failed to wakeup (%d)\n"), status);
+ }
+
+
+ /* Wait forever */
+ while (1)
+ {
+ atomTimerDelay (SYSTEM_TICKS_PER_SEC);
+ }
+}
+
+
+
+static int event_set_rx_flag()
+{
+ int status;
+
+ printf("event_set_rx_flag atom_event_current 0x%8x \n",(unsigned int)event2.atom_event_current);
+ if ((status = atomEventSet(&event2, RX_COMPLETE_FLAG,ATOM_OR)) != ATOM_OK)
+ {
+ ATOMLOG (_STR("event_set_rx_flag (%d)\n"), status);
+ }
+ return status;
+}
+
+
+static int event_set_tx_flag()
+{
+ int status;
+
+
+ printf("event_set_tx_flag atom_event_current 0x%8x\n",(unsigned int)event2.atom_event_current);
+ if ((status = atomEventSet(&event2, TX_COMPLETE_FLAG,ATOM_OR)) != ATOM_OK)
+ {
+ ATOMLOG (_STR("event_set_tx_flag failed (%d)\n"), status);
+ }
+
+ return status;
+
+}
diff --git a/tests/event2.c b/tests/event2.c
new file mode 100755
index 00000000..8c0309f5
--- /dev/null
+++ b/tests/event2.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017, jinsong yu, ramaxel. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. No personal names or organizations' names associated with the
+ * Atomthreads project may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "atom.h"
+#include "atomevent.h"
+#include "atomtests.h"
+
+
+
+
+#define RX_COMPLETE_FLAG 0x01
+#define TX_COMPLETE_FLAG 0x02
+
+
+/* Number of test threads */
+#define NUM_TEST_THREADS 2
+
+
+/* Test OS objects */
+static ATOM_EVENT event1;
+static ATOM_TCB tcb[NUM_TEST_THREADS];
+static uint8_t test_thread_stack[NUM_TEST_THREADS][TEST_THREAD_STACK_SIZE];
+
+
+/* Forward declarations */
+static void test1_thread_func (uint32_t param);
+
+
+
+/**
+ * \b test_start
+ *
+ * Start event test.
+ *
+ * This test exercises the event creation and deletion APIs, including
+ * waking threads blocking on a event if the event is deleted.
+ * Deletion wakeups are tested twice: once for a thread which is blocking
+ * with a timeout and once for a thread which is blocking with no timeout.
+ *
+ * @retval Number of failures
+ */
+uint32_t test_start (void)
+{
+ int failures;
+ int i;
+ failures = 0;
+
+
+ /* Test creation and deletion of event: good values */
+ for (i = 0; i < 1000; i++)
+ {
+ if (atomEventCreate (&event1, "event1") == ATOM_OK)
+ {
+ if (atomEventDelete (&event1) == ATOM_OK)
+ {
+ /* Success */
+ }
+ else
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error deleting event1\n"));
+ failures++;
+ break;
+ }
+ }
+ else
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error creating event1\n"));
+ failures++;
+ break;
+ }
+ }
+ ATOMLOG (_STR("stress test for 1000 times atomEventCreate/atomEventDelete passed! \n"));
+
+ /* Test creation and deletion of event: creation checks */
+ if (atomEventCreate (NULL, 0) != ATOM_OK)
+ {
+ /* Success */
+ }
+ else
+ {
+ /* Fail */
+ ATOMLOG (_STR("Bad event creation checks\n"));
+ failures++;
+ }
+
+ /* Test creation and deletion of event: deletion checks */
+ if (atomEventDelete (NULL) != ATOM_OK)
+ {
+ /* Success */
+ }
+ else
+ {
+ /* Fail */
+ ATOMLOG (_STR("Bad event deletion checks\n"));
+ failures++;
+ }
+
+ ATOMLOG (_STR("atomEventCreate/atomEventDelete parameter passed. \n"));
+
+
+ /* Test wakeup of threads on event deletion (thread blocking with no timeout) */
+ if (atomEventCreate (&event1, "event1") != ATOM_OK)
+ {
+ ATOMLOG (_STR("Error creating test event 1\n"));
+ failures++;
+ }
+
+
+ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0,
+ &test_thread_stack[0][0],
+ TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error creating test thread 1\n"));
+ failures++;
+ }
+ else
+ {
+
+ /*
+ * We have created two event. sem1 is for the other thread
+ * to wait on, which we will delete from this thread. We want
+ * to see that the other thread is woken up if its event
+ * is deleted. This is indicated through event being posted
+ * back to us.
+ */
+
+ /* Wait for the other thread to start blocking on sem1 */
+ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Failed timer delay\n"));
+ failures++;
+ }
+ else
+ {
+ ATOMLOG (_STR("atomEventDelete event\n"));
+ /* The other thread will be blocking on sem1 now, delete sem1 */
+ if (atomEventDelete(&event1) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Failed event1 delete\n"));
+ failures++;
+ }
+ else
+ {
+ /* delay and let thread1 to get the delete flag. */
+ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Failed timer delay\n"));
+ failures++;
+ }
+ }
+ }
+ }
+
+
+ /* Check thread stack usage (if enabled) */
+#ifdef ATOM_STACK_CHECKING
+ {
+ uint32_t used_bytes, free_bytes;
+ int thread;
+
+ /* Check all threads */
+ for (thread = 0; thread < NUM_TEST_THREADS; thread++)
+ {
+ /* Check thread stack usage */
+ if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
+ {
+ ATOMLOG (_STR("StackCheck\n"));
+ failures++;
+ }
+ else
+ {
+ /* Check the thread did not use up to the end of stack */
+ if (free_bytes == 0)
+ {
+ ATOMLOG (_STR("StackOverflow %d\n"), thread);
+ failures++;
+ }
+
+ /* Log the stack usage */
+#ifdef TESTS_LOG_STACK_USAGE
+ ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
+#endif
+ }
+ }
+ }
+#endif
+
+ /* Quit */
+ return failures;
+}
+
+/**
+ * \b test1_thread_func
+ *
+ * Entry point for test thread 1.
+ *
+ * @param[in] param Unused (optional thread entry parameter)
+ *
+ * @return None
+ */
+static void test1_thread_func (uint32_t param)
+{
+ uint8_t status;
+ uint32_t actual_flags_ptr;
+
+ /* Compiler warnings */
+ param = param;
+
+ /*
+ * Wait on event with no timeout. We are expecting to be woken up
+ * by the main thread delete while blocking.
+ */
+ status = atomEventGet(&event1, (RX_COMPLETE_FLAG | RX_COMPLETE_FLAG),ATOM_AND_CLEAR,&actual_flags_ptr,ATOM_WAIT_FOREVER);//wait wait option 0 is failed.
+ if (status != ATOM_ERR_DELETED)
+ {
+ ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status);
+ }
+ else
+ {
+ ATOMLOG (_STR("unblock the thread by delete the event \n"));
+ }
+
+ /* Wait forever */
+ while (1)
+ {
+ atomTimerDelay (SYSTEM_TICKS_PER_SEC);
+ }
+}
+
diff --git a/tests/event3.c b/tests/event3.c
new file mode 100755
index 00000000..d98a627e
--- /dev/null
+++ b/tests/event3.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2017 jinsong yu, ramaxel. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. No personal names or organizations' names associated with the
+ * Atomthreads project may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "atom.h"
+#include "atomtests.h"
+#include "atomevent.h"
+
+
+/* Number of test threads */
+#define NUM_TEST_THREADS 3
+
+#define RX_COMPLETE_FLAG 0x01
+#define TX_COMPLETE_FLAG 0x02
+
+/* Test OS objects */
+static ATOM_EVENT event1;
+static ATOM_TCB tcb[NUM_TEST_THREADS];
+static uint8_t test_thread_stack[NUM_TEST_THREADS][TEST_THREAD_STACK_SIZE];
+
+
+/* Test running flag */
+static volatile int test_running;
+
+
+/* Forward declarations */
+static void test_thread_func (uint32_t param);
+static void testCallback (POINTER cb_data);
+
+
+/**
+ * \b test_start
+ *
+ * Start event3 test.
+ *
+ * This stress-tests atomEventGet()/atomEventSet() with a timer ticker callback
+ * continually calling atom_event_set() and several contexts continually
+ * calling atomEventGet(). This stresses in particular the atomEventGet()
+ * API, with one threads and main thread at different priorities get
+ * simultaneously, as well as a timer callback set it from
+ * interrupt context. In all cases the event is successful to get and set.
+ *
+ * This tests the thread-safety and interrupt-safety of the event
+ * APIs.
+ *
+ * @retval Number of failures
+ */
+uint32_t test_start (void)
+{
+ int failures;
+ uint32_t end_time,count;
+ ATOM_TIMER timer_cb;
+ uint32_t requested_flags;
+ uint32_t actual_flags_ptr;
+ requested_flags = (RX_COMPLETE_FLAG | RX_COMPLETE_FLAG);
+
+ /* Default to zero failures */
+ failures = 0;
+ count = 0;
+
+ /* Create sem with count of zero */
+ if (atomEventCreate(&event1, "event1") != ATOM_OK)
+
+ {
+ ATOMLOG (_STR("Error creating test event 1\n"));
+ failures++;
+ }
+ else
+ {
+ /* Set the test running flag */
+ test_running = TRUE;
+
+ /*
+ * Fill out a timer callback request structure. Pass the timer
+ * structure itself so that the callback can requeue the request.
+ */
+ timer_cb.cb_func = testCallback;
+ timer_cb.cb_data = &timer_cb;
+ timer_cb.cb_ticks = 1;
+
+ /*
+ * Request a timer callback to run in one tick's time. The callback
+ * will automatically queue another so that this happens repeatedly
+ * until the test is flagged as finished.
+ */
+ if (atomTimerRegister (&timer_cb) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Error registering timer\n"));
+ failures++;
+ }
+
+ /* Create thread 1 */
+ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO , test_thread_func, 1,
+ &test_thread_stack[0][0],
+ TEST_THREAD_STACK_SIZE, TRUE) != ATOM_OK)
+ {
+ /* Fail */
+ ATOMLOG (_STR("Error creating test thread 1\n"));
+ failures++;
+ }
+
+ /* The test threads have now all been created */
+ else
+ {
+ /*
+ * Continually decrement the event while the test threads
+ * and timer callbacks are continually incrementing it. The
+ * test finishes after this runs without error for 5 seconds.
+ */
+ end_time = atomTimeGet() + (60*60*15 * SYSTEM_TICKS_PER_SEC);
+ while (atomTimeGet() < end_time)
+ {
+ /* Decrement the event */
+ if(atomEventGet(&event1, requested_flags,ATOM_AND_CLEAR,&actual_flags_ptr,3*SYSTEM_TICKS_PER_SEC)!=ATOM_OK)//ATOM_WAIT_FOREVER
+ {
+ ATOMLOG (_STR("atomEventGet failure, actual_flags_ptr %d \n"),(int)actual_flags_ptr);
+ failures++;
+ break;
+ }
+ count++;
+ if(count%100 == 0)
+ {
+ ATOMLOG (_STR("atomEventGet atomTimeGet success, count %d \n"),(int)count);
+ }
+ }
+
+ /* Test finished, stop the other threads and timer callbacks */
+ test_running = FALSE;
+
+ /*
+ * Wait before finishing: a timer callback could be due
+ * shortly, and we allocated the timer structure off the
+ * local call stack.
+ */
+ atomTimerDelay(2);
+
+ }
+ if (atomEventDelete (&event1) != ATOM_OK)
+ {
+ ATOMLOG (_STR("Delete failed\n"));
+ failures++;
+ }
+ }
+
+
+
+
+ /* Check thread stack usage (if enabled) */
+#ifdef ATOM_STACK_CHECKING
+ {
+ uint32_t used_bytes, free_bytes;
+ int thread;
+
+ /* Check all threads */
+ for (thread = 0; thread < NUM_TEST_THREADS; thread++)
+ {
+ /* Check thread stack usage */
+ if (atomThreadStackCheck (&tcb[thread], &used_bytes, &free_bytes) != ATOM_OK)
+ {
+ ATOMLOG (_STR("StackCheck\n"));
+ failures++;
+ }
+ else
+ {
+ /* Check the thread did not use up to the end of stack */
+ if (free_bytes == 0)
+ {
+ ATOMLOG (_STR("StackOverflow %d\n"), thread);
+ failures++;
+ }
+
+ /* Log the stack usage */
+#ifdef TESTS_LOG_STACK_USAGE
+ ATOMLOG (_STR("StackUse:%d\n"), (int)used_bytes);
+#endif
+ }
+ }
+ }
+#endif
+
+ /* Quit */
+ return failures;
+
+}
+
+
+/**
+ * \b test_thread_func
+ *
+ * Entry point for test thread.
+ *
+ * @param[in] param sleep_flag passed through here
+ *
+ * @return None
+ */
+static void test_thread_func (uint32_t param)
+{
+ int failures,count;
+ uint32_t requested_flags;
+ uint32_t actual_flags_ptr;
+ requested_flags = (RX_COMPLETE_FLAG | RX_COMPLETE_FLAG);
+
+ /* Were we requested to sleep occasionally? */
+ param = (int)param;
+
+ /* Run until the main thread sets the finish flag or we get an error */
+ failures = 0;
+
+ while ((test_running == TRUE) && (failures == 0))
+ {
+ /* get the event each 2 system time ticks */
+
+ if(atomEventGet(&event1, requested_flags,ATOM_AND_CLEAR,&actual_flags_ptr,2*SYSTEM_TICKS_PER_SEC)!=ATOM_OK)//ATOM_WAIT_FOREVER
+ {
+ ATOMLOG (_STR("atomEventGet failure, actual_flags_ptr %d \n"),(int)actual_flags_ptr);
+ failures++;
+ break;
+ }
+ count++;
+ if(count%100 == 0)
+ {
+ ATOMLOG (_STR("atomEventGet test_thread_func success, count %d \n"),(int)count);
+ }
+ }
+
+ /* Loop forever */
+ while (1)
+ {
+ atomTimerDelay (SYSTEM_TICKS_PER_SEC);
+ }
+}
+
+
+/**
+ * \b testCallback
+ *
+ * set the event from interrupt context. This will be occurring while
+ * atomEventGet() calls for 2 threads are in progress,
+ *
+ * Automatically requeues itself for one tick in the future, so this
+ * continually fires until the finish flag is set.
+ *
+ * @param[in] cb_data Pointer to the original ATOM_TIMER structure
+ */
+static void testCallback (POINTER cb_data)
+{
+ ATOM_TIMER *ptimer;
+ uint8_t status;
+ /* Pull out the original timer request */
+ ptimer = (ATOM_TIMER *)cb_data;
+
+ /* set event1 */
+ if ((status = atomEventSet(&event1, RX_COMPLETE_FLAG||TX_COMPLETE_FLAG,ATOM_OR)) != ATOM_OK)
+ {
+ ATOMLOG (_STR("atomEventGet failure, actual_flags_ptr %d \n"),(int)status);
+ }
+
+ /* Enqueue another timer callback in one tick's time */
+ if (test_running == TRUE)
+ {
+ /* Update the callback time and requeue */
+ ptimer->cb_ticks = 1;
+ if (atomTimerRegister (ptimer) != ATOM_OK)
+ {
+ }
+ }
+ else
+ {
+ /* Test finished, no more will be queued */
+ }
+
+}