/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; /* Compiler warnings */ param = param; /* * Take mutex2 so that main thread can test mutex APIs on a mutex * which it does not own. */ status = atomMutexGet(&mutex2, 0); if (status != ATOM_OK) { ATOMLOG (_STR("Mutex get (%d)\n"), status); } else { /* We took ownership of mutex2, set g_owned to notify success */ g_owned = 1; } /* Wait forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread_func * * Entry point for test thread. The same thread entry point is used for all * four test threads, with the thread number/ID (1-4) passed as the entry * point parameter. * * @param[in] param Thread number (1,2,3,4) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t thread_id; /* Thread ID is passed through the function parameter */ thread_id = (uint8_t)param; /* * Wait for sem1 to be posted. At creation of all test threads * the semaphore count is zero, so all four threads will block * here. */ if (atomSemGet (&sem1, 0) != ATOM_OK) { ATOMLOG (_STR("Thread sem fail\n")); } else { /* * Store our thread ID in the array using the current * wake_cnt order. The threads are deliberately woken up * some time apart to ensure that no protection is required * on this global data. */ wake_order[wake_cnt++] = thread_id; } /* Loop forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread_func * * Entry point for test threads. * * @param[in] param Thread ID (0-2) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; uint8_t msg; int thread_id; /* Pull out the passed thread ID */ thread_id = (int)param; /* * Wait on queue1 with timeout. We are expecting to be woken up * by the main thread while blocking. */ status = atomQueueGet(&queue1, (5 * SYSTEM_TICKS_PER_SEC), &msg); if (status != ATOM_ERR_DELETED) { ATOMLOG (_STR("Test1 thread woke without deletion (%d)\n"), status); } else { /* We were woken due to deletion as expected, set pass_flag to notify success */ pass_flag[thread_id] = TRUE; } /* 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, msg; /* Compiler warnings */ param = param; /* * Wait on queue1 with timeout. We are expecting to be woken up * by the main thread while blocking. */ status = atomQueueGet(&queue1, (5 * SYSTEM_TICKS_PER_SEC), &msg); if (status != ATOM_ERR_DELETED) { ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status); } else { /* We were woken due to deletion as expected, set g_result to notify success */ g_result = 1; } /* 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, msg; /* Compiler warnings */ param = param; /* Set a test value for posting to the queue */ msg = 0x66; /* * Post to queue1 with timeout. The queue should be full so * we are expecting to block. We should then be woken up by the * main thread while blocking. */ status = atomQueuePut(&queue1, (5 * SYSTEM_TICKS_PER_SEC), &msg); if (status != ATOM_ERR_DELETED) { ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status); } else { /* We were woken due to deletion as expected, set g_result to notify success */ g_result = 1; } /* 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; /* Compiler warnings */ param = param; /* * Wait on sem1 with timeout. We are expecting to be woken up * by the main thread while blocking. */ status = atomSemGet(&sem1, (5 * SYSTEM_TICKS_PER_SEC)); if (status != ATOM_ERR_DELETED) { ATOMLOG (_STR("Test2 thread woke without deletion (%d)\n"), status); } else { /* We were woken due to deletion as expected, post sem2 to notify success */ if ((status = atomSemPut(&sem2)) != ATOM_OK) { ATOMLOG (_STR("Error posting sem2 on wakeup\n")); } } /* Wait forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; /* Compiler warnings */ param = param; /* Block on the mutex */ if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK) { /* Error getting mutex, notify the status code */ ATOMLOG (_STR("G%d\n"), status); } /* Got the mutex */ else { /* Set shared_data to signify that we think we have the mutex */ shared_data = 1; } /* Loop forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread_func * * Entry point for test thread. The same thread entry point is used for all * three test threads, with the thread number/ID (1-3) passed as the entry * point parameter. * * @param[in] param Thread number (1,2,3) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t thread_id; uint32_t start_time, end_time; /* Thread ID is passed through the function parameter */ thread_id = (uint8_t)param; /* * Sleep for 1 tick to ensure that the thread starts near * a timer tick boundary. This ensures that the system * tick does not advance between the atomTimeGet() call * and the actual atomTimerDelay() call being made. */ atomTimerDelay (1); /* Loop running the test forever */ while (1) { /* Record the start time */ start_time = atomTimeGet(); /* Sleep for n ticks, where n is the thread ID */ if (atomTimerDelay(thread_id) != ATOM_OK) { g_failure_cnt[thread_id-1]++; } else { /* Record the time we woke up */ end_time = atomTimeGet(); /* Check that time has advanced by exactly n ticks */ if ((end_time - start_time) != thread_id) { g_failure_cnt[thread_id-1]++; } } } }
/** * \b main_thread_func * * Entry point for main application thread. * * This is the first thread that will be executed when the OS is started. * * @param[in] data Unused (optional thread entry parameter) * * @return None */ static void main_thread_func (uint32_t data) { uint32_t test_status; /* Put a message out on the UART */ ATOMLOG("Go\n"); /* Start test. All tests use the same start API. */ test_status = test_start(); /* Check main thread stack usage (if enabled) */ #ifdef ATOM_STACK_CHECKING if (test_status == 0) { uint32_t used_bytes, free_bytes; /* Check idle thread stack usage */ if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK) { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { ATOMLOG("Main stack overflow\n"); test_status++; } /* Log the stack usage */ #ifdef TESTS_LOG_STACK_USAGE ATOMLOG("MainUse:%d\n", used_bytes); #endif } } #endif /* Log final status */ if (test_status == 0) { ATOMLOG("Pass\n"); } else { ATOMLOG("Fail(%d)\n", test_status); } /* Test finished, sit idle */ while (1) { atomTimerDelay(SYSTEM_TICKS_PER_SEC); } }
/** * \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) { uint32_t msg; int num_entries, count, failures; /* Compiler warnings */ param = param; /* Default to no errors */ failures = 0; /* * Loop receiving messages until we have received the number of * values in the test array. */ num_entries = sizeof(test_values) / sizeof(test_values[0]); for (count = 0; count < num_entries; count++) { /* Receive a value from the queue */ if (atomQueueGet (&queue1, 0, (uint8_t *)&msg) != ATOM_OK) { ATOMLOG (_STR("Failed get\n")); failures++; } /* Check that we received the expected value */ else if (msg != test_values[count]) { ATOMLOG (_STR("Val%d\n"), count); failures++; } } /* * Set g_result to indicate success if we had no failures. * Thread-protection is not required on g_result because it * is only ever set by this thread. */ if (failures == 0) { /* No failures */ g_result = 1; } /* Wait forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread * * Function calling the test function of the Atomthreads test suite. * */ void test_thread (uint32_t param) { uint32_t failures ; CRITICAL_STORE ; failures = test_start () ; atomTimerDelay (10) ; CRITICAL_START() ; printf ("%s %s\r\n", ATOMTHREADS_TEST, failures ? "FAIL" : "PASS") ; exit (failures) ; CRITICAL_END() ; }
/** * \b test_thread_func * * Entry point for test thread. The same thread entry point is used for all * four test threads. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint32_t loop_cnt; uint8_t status; CRITICAL_STORE; /* Compiler warnings */ param = param; /* Run a Get/Put pair many times */ loop_cnt = NUM_TEST_LOOPS; while (loop_cnt--) { if ((status = atomMutexGet (&mutex1, 0)) != ATOM_OK) { /* Error getting mutex, notify the status code */ ATOMLOG (_STR("G%d\n"), status); CRITICAL_START (); g_failures++; CRITICAL_END (); break; } else if ((status = atomMutexPut (&mutex1)) != ATOM_OK) { /* Error putting mutex, notify the status code */ ATOMLOG (_STR("P%d\n"), status); CRITICAL_START (); g_failures++; CRITICAL_END (); break; } } /* Post sem1 to notify the main thread we're finished */ if (atomSemPut (&sem1) != ATOM_OK) { ATOMLOG (_STR("Sem1 putfail\n")); CRITICAL_START (); g_failures++; CRITICAL_END (); } /* Loop forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; int count; int failures; /* Compiler warnings */ param = param; /* * Attempt to decrement sem1 ten times, which should happen immediately * each time. */ failures = 0; count = INITIAL_SEM_COUNT; while (count--) { /* Decrement sem1 */ if ((status = atomSemGet (&sem1, -1)) != ATOM_OK) { /* Error decrementing semaphore, notify the status code */ ATOMLOG (_STR("G%d\n"), status); failures++; } } /* Check above stage was successful */ if (failures == 0) { /* Sem1 should now have a count of zero, and not allow a decrement */ if ((status = atomSemGet (&sem1, -1)) != ATOM_WOULDBLOCK) { /* Error getting semaphore, notify the status code */ ATOMLOG (_STR("W%d\n"), status); } /* Post sem2 to notify that the test passed */ else if ((status = atomSemPut (&sem2)) != ATOM_OK) { /* Error putting semaphore, notify the status code */ ATOMLOG (_STR("P%d\n"), status); } } /* Loop forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
u8 flashEraseSector(u32 sector) { u32 sectorAddr = ((u32)sector << 12); u8 timeout=TIMEOUT; flashWriteEnable(); //开启写使能 FILECS_LOW; //使能设备 spiSendByte(SECTOR_ERA_COM); //扇区擦除 spiSendByte((u8)(sectorAddr>>16)); //发送地址 spiSendByte((u8)(sectorAddr>>8)); //发送地址 spiSendByte((u8)(sectorAddr)); //发送地址 FILECS_HIGH; //禁能设备 while (flashReadStateCom()&STATUS_WIP){ atomTimerDelay (1); if (0==(timeout--))break; } return 0x01; }
/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Unused (optional thread entry parameter) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t status; /* Compiler warnings */ param = param; /* Repeatedly attempt to get the mutex and set shared_data to 1 */ while (1) { /* Block on the mutex sem1 */ if ((status = atomSemGet (&sem1, 0)) != ATOM_OK) { /* Error getting semaphore, notify the status code */ ATOMLOG (_STR("G%d\n"), status); break; } /* Got the mutex */ else { /* Set shared_data to signify that we think we have the mutex */ shared_data = 1; /* Release the mutex allowing the main thread to take it again */ if ((status = atomSemPut (&sem1)) != ATOM_OK) { /* Error putting semaphore, notify the status code */ ATOMLOG (_STR("P%d\n"), status); break; } } } /* Loop forever - we only reach here on error */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/** * \b test_thread_func * * Entry point for test thread. * * @param[in] param Thread ID (0 = low prio, 1 = high prio) * * @return None */ static void test_thread_func (uint32_t param) { int thread_id; /* Pull out thread ID */ thread_id = (int)param; /* Run forever */ while (1) { /* If this thread is requested to sleep, sleep until told to stop */ if (sleep_request[thread_id]) { atomTimerDelay (1); } else { /* Otherwise set running flag for this thread */ running_flag[thread_id] = TRUE; } } }
/** * \b test_thread_func * * Entry point for test thread. The same thread entry point is used for all * four test threads, with the thread number/ID (1-4) passed as the entry * point parameter. * * @param[in] param Thread number (1,2,3,4) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t thread_id; /* Thread ID is passed through the function parameter */ thread_id = (uint8_t)param; /* * Wait for mutex1 to be posted. At creation of all test threads the mutex * is owned by the parent thread, so all four threads will block here. */ if (atomMutexGet (&mutex1, 0) != ATOM_OK) { ATOMLOG (_STR("Get fail\n")); } else { /* * Store our thread ID in the array using the current * wake_cnt order. The threads are holding ownership * of a mutex here, which provides protection for this * global data. */ wake_order[wake_cnt++] = thread_id; /* Release the mutex so that the next thread wakes up */ if (atomMutexPut (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Put fail\n")); } } /* Loop forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
/* * flash最多写一个page,256字节 * *buf数据指针 * pageAddr写入地址 (不一定是page头) * writeNum写入数据byte量 */ void flashWritePage(u8 *buf, u32 pageAddr, u16 writeNum) { u8 timeout=TIMEOUT; flashWriteEnable(); FILECS_LOW; //使能设备 spiSendByte(PAGE_PRO_COM); //发送写数据命令 spiSendByte((u8)(pageAddr>>16)); //发送地址 spiSendByte((u8)(pageAddr>>8)); //发送地址 spiSendByte((u8)(pageAddr)); //发送地址 for (u16 i=0; i<writeNum; i++){ spiSendByte(*buf); //数据发送 buf++; } FILECS_HIGH; while (flashReadStateCom()&STATUS_WIP){ atomTimerDelay (1); if (0==(timeout--))break; } }
/** * \b test_thread_func * * Entry point for test thread. The same thread entry point is used for all * four test threads, with the thread number/ID (1-4) passed as the entry * point parameter. * * @param[in] param Thread number (1,2,3,4) * * @return None */ static void test_thread_func (uint32_t param) { uint8_t thread_id; uint8_t msg; /* Thread ID is passed through the function parameter */ thread_id = (uint8_t)param; /* * Wait for a message to appear on queue1. At creation of all test * threads the queue is empty, so all four threads will block here. */ if (atomQueueGet (&queue1, 0, &msg) != ATOM_OK) { ATOMLOG (_STR("Get fail\n")); } else { /* * Store our thread ID in the array using the current * wake_cnt order. The threads are woken with large * pauses between, which provides protection for this * global data. This allows us to test queues without * assuming a working implementation of a mutex (or * similar protection mechanism). */ wake_order[wake_cnt++] = thread_id; } /* Loop forever */ while (1) { atomTimerDelay (SYSTEM_TICKS_PER_SEC); } }
void clock_update_func (uint32_t data) { while(1) { // Increment time (global variables protected by mutex lock) if (atomMutexGet(&clock_mutex, 0) == ATOM_OK) { g_sec++; if (g_sec > 59) { g_sec = 0; g_min++; if (g_min > 59) { g_min = 0; g_hour++; if (g_hour > 23) g_hour = 0; } } } atomMutexPut(&clock_mutex); atomTimerDelay(100); } }
/** * \b test_start * * Start mutex test. * * This test exercises the atomMutexGet() and atomMutexPut() APIs including * forcing the various error indications which can be returned from the * APIs to ensure that handling for these corner cases have been correctly * implemented. * * @retval Number of failures */ uint32_t test_start (void) { int failures; uint8_t status; ATOM_TIMER timer_cb; int count; /* Default to zero failures */ failures = 0; /* Test parameter checks */ if (atomMutexGet (NULL, 0) != ATOM_ERR_PARAM) { ATOMLOG (_STR("Get param failed\n")); failures++; } if (atomMutexPut (NULL) != ATOM_ERR_PARAM) { ATOMLOG (_STR("Put param failed\n")); failures++; } /* Test atomMutexGet() can not be called from interrupt context */ g_result = 0; if (atomMutexCreate (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Error creating test mutex1\n")); failures++; } else { /* Fill out the timer callback request structure */ timer_cb.cb_func = testCallback; timer_cb.cb_data = NULL; timer_cb.cb_ticks = SYSTEM_TICKS_PER_SEC; /* Request the timer callback to run in one second */ if (atomTimerRegister (&timer_cb) != ATOM_OK) { ATOMLOG (_STR("Error registering timer\n")); failures++; } /* Wait two seconds for g_result to be set indicating success */ else { atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC); if (g_result != 1) { ATOMLOG (_STR("Context check failed\n")); failures++; } } /* Delete the test mutex */ if (atomMutexDelete (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Mutex1 delete failed\n")); failures++; } } /* Create mutex1 which will be owned by us */ if (atomMutexCreate (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Error creating test mutex 1\n")); failures++; } /* Create mutex2 which will be owned by another thread */ else if (atomMutexCreate (&mutex2) != ATOM_OK) { ATOMLOG (_STR("Error creating test mutex 2\n")); failures++; } /* Create a test thread, the sole purpose of which is to own mutex2 */ g_owned = 0; if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 1\n")); failures++; } /* Sleep until the test thread owns mutex2 */ atomTimerDelay (SYSTEM_TICKS_PER_SEC); if (g_owned == 0) { ATOMLOG (_STR("Thread own fail\n")); failures++; } /* Test wait on mutex with timeout - should timeout while owned by another thread */ if ((status = atomMutexGet (&mutex2, SYSTEM_TICKS_PER_SEC)) != ATOM_TIMEOUT) { ATOMLOG (_STR("Get %d\n"), status); failures++; } else { /* Success */ } /* Test wait on mutex with no blocking - should return that owned by another thread */ if ((status = atomMutexGet (&mutex2, -1)) != ATOM_WOULDBLOCK) { ATOMLOG (_STR("Wouldblock err %d\n"), status); failures++; } /* Test wait on mutex with no blocking when mutex is available */ if (atomMutexGet (&mutex1, -1) != ATOM_OK) { ATOMLOG (_STR("Error taking mutex1\n")); failures++; } else { /* Relinquish ownership of mutex1 */ if (atomMutexPut (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Error posting mutex\n")); failures++; } } /* Test for lock count overflows with too many gets */ count = 255; while (count--) { if (atomMutexGet (&mutex1, 0) != ATOM_OK) { ATOMLOG (_STR("Error getting mutex1\n")); failures++; break; } } /* The lock count should overflow this time */ if (atomMutexGet (&mutex1, 0) != ATOM_ERR_OVF) { ATOMLOG (_STR("Error tracking overflow\n")); failures++; } else { /* Success */ } /* Delete the test mutexes */ if (atomMutexDelete (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Error deleting mutex1\n")); failures++; } if (atomMutexDelete (&mutex2) != ATOM_OK) { ATOMLOG (_STR("Error deleting mutex2\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 main_thread_func * * Entry point for main application thread. * * This is the first thread that will be executed when the OS is started. * * @param[in] data Unused (optional thread entry parameter) * * @return None */ static void main_thread_func (uint32_t data) { uint32_t test_status; int sleep_ticks; /* Enable all LEDs (STK500-specific) */ DDRB = 0xFF; PORTB = 0xFF; /* Initialise UART (9600bps) */ if (uart_init(9600) != 0) { /* Error initialising UART */ } /** * Redirect stdout via the UART. Note that the UART write routine * is protected via a semaphore, so the OS must be started before * use of the UART. */ stdout = &uart_stdout; /* Put a message out on the UART */ printf_P(PSTR("Go\n")); /* Start test. All tests use the same start API. */ //test_status = test_start(); /* Check main thread stack usage (if enabled) */ #ifdef ATOM_STACK_CHECKING if (test_status == 0) { uint32_t used_bytes, free_bytes; /* Check idle thread stack usage */ if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK) { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { printf_P (PSTR("Main stack overflow\n")); test_status++; } /* Log the stack usage */ #ifdef TESTS_LOG_STACK_USAGE printf_P (PSTR("MainUse:%d\n"), used_bytes); #endif } } #endif /* Log final status */ if (test_status == 0) { printf_P (PSTR("Pass\n")); } else { printf_P (PSTR("Fail(%d)\n"), test_status); } /* Flash LED once per second if passed, very quickly if failed */ sleep_ticks = (test_status == 0) ? SYSTEM_TICKS_PER_SEC : (SYSTEM_TICKS_PER_SEC/8); /* Test finished, flash slowly for pass, fast for fail */ while (1) { /* Toggle a LED (STK500-specific) */ PORTB ^= (1 << 7); /* Sleep then toggle LED again */ atomTimerDelay(sleep_ticks); } }
/** * \b test_start * * Start semaphore test. * * This test exercises the semaphore creation and deletion APIs, including * waking threads blocking on a semaphore if the semaphore 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; uint32_t i; uint8_t status; /* Default to zero failures */ failures = 0; /* Test creation and deletion of semaphores: good values */ for (i = 0; i < 1000; i++) { if (atomSemCreate (&sem1, 0) == ATOM_OK) { if (atomSemDelete (&sem1) == ATOM_OK) { /* Success */ } else { /* Fail */ ATOMLOG (_STR("Error deleting semaphore\n")); failures++; break; } } else { /* Fail */ ATOMLOG (_STR("Error creating semaphore\n")); failures++; break; } } /* Test creation and deletion of semaphores: creation checks */ if (atomSemCreate (NULL, 0) != ATOM_OK) { /* Success */ } else { /* Fail */ ATOMLOG (_STR("Bad semaphore creation checks\n")); failures++; } /* Test creation and deletion of semaphores: deletion checks */ if (atomSemDelete (NULL) != ATOM_OK) { /* Success */ } else { /* Fail */ ATOMLOG (_STR("Bad semaphore deletion checks\n")); failures++; } /* Test wakeup of threads on semaphore deletion (thread blocking with no timeout) */ if (atomSemCreate (&sem1, 0) != ATOM_OK) { ATOMLOG (_STR("Error creating test semaphore 1\n")); failures++; } else if (atomSemCreate (&sem2, 0) != ATOM_OK) { ATOMLOG (_STR("Error creating test semaphore 2\n")); failures++; } else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 1\n")); failures++; } else { /* * We have created two semaphores. 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 semaphore * is deleted. This is indicated through sem2 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 { /* The other thread will be blocking on sem1 now, delete sem1 */ if (atomSemDelete(&sem1) != ATOM_OK) { ATOMLOG (_STR("Failed sem1 delete\n")); failures++; } else { /* Sem1 deleted. The thread should now wake up and post sem2. */ if ((status = atomSemGet (&sem2, (5*SYSTEM_TICKS_PER_SEC))) != ATOM_OK) { ATOMLOG (_STR("Notify fail (%d)\n"), status); failures++; } else { /* Success */ /* Clean up the last remaining semaphore */ if (atomSemDelete (&sem2) != ATOM_OK) { ATOMLOG (_STR("Failed sem2 delete\n")); failures++; } } } } } /* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */ if (atomSemCreate (&sem1, 0) != ATOM_OK) { ATOMLOG (_STR("Error creating test semaphore 1\n")); failures++; } else if (atomSemCreate (&sem2, 0) != ATOM_OK) { ATOMLOG (_STR("Error creating test semaphore 2\n")); failures++; } else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 2\n")); failures++; } else { /* * We have created two semaphores. 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 semaphore * is deleted. This is indicated through sem2 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 { /* The other thread will be blocking on sem1 now, delete sem1 */ if (atomSemDelete(&sem1) != ATOM_OK) { ATOMLOG (_STR("Failed sem1 delete\n")); failures++; } else { /* Sem1 deleted. The thread should now wake up and post sem2. */ if ((status = atomSemGet (&sem2, (5*SYSTEM_TICKS_PER_SEC))) != ATOM_OK) { ATOMLOG (_STR("Notify fail (%d)\n"), status); failures++; } else { /* Success */ /* Clean up the last remaining semaphore */ if (atomSemDelete (&sem2) != ATOM_OK) { ATOMLOG (_STR("Failed sem2 delete\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_start * * Start queue test. * * This test exercises queue deletion, waking threads blocking on a queue * in atomQueuePut() if the queue is deleted. * * Deletion wakeups are tested twice: once for a thread which is blocking * in atomQueuePut() with a timeout and once for a thread which is * blocking in atomQueuePut() with no timeout. * * Deletion of threads blocking in atomQueueGet() are tested in queue2.c. * * @retval Number of failures */ uint32_t test_start (void) { int failures, i; uint8_t msg; /* Default to zero failures */ failures = 0; /* Set a test value for posting to the queue */ msg = 0x66; /* Test wakeup of threads on queue deletion (thread blocking with no timeout) */ g_result = 0; if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK) { ATOMLOG (_STR("Error creating test queue\n")); failures++; } /* Successful queue creation */ else { /* Fill up all entries */ for (i = 0; i < QUEUE_ENTRIES; i++) { if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK) { ATOMLOG (_STR("Error filling queue\n")); failures++; } } /* Create a test thread that will block because the queue is full */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 1\n")); failures++; } else { /* * We have created and filled a queue. We want to see that the other * thread is woken up if its queue is deleted. This is indicated * through g_result being set. */ /* Wait for the other thread to start blocking on queue1 */ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK) { ATOMLOG (_STR("Failed timer delay\n")); failures++; } else { /* The other thread will be blocking on queue1 now, delete queue1 */ if (atomQueueDelete(&queue1) != ATOM_OK) { ATOMLOG (_STR("Failed queue1 delete\n")); failures++; } else { /* Queue1 deleted. The thread should now wake up and set g_result. */ atomTimerDelay (SYSTEM_TICKS_PER_SEC); if (g_result == 0) { ATOMLOG (_STR("Notify fail\n")); failures++; } else { /* Success */ } } } } } /* Test wakeup of threads on semaphore deletion (thread blocking with timeout) */ g_result = 0; if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(uint8_t), QUEUE_ENTRIES) != ATOM_OK) { ATOMLOG (_STR("Error creating test queue\n")); failures++; } /* Successful queue creation */ else { /* Fill up all entries */ for (i = 0; i < QUEUE_ENTRIES; i++) { if (atomQueuePut (&queue1, 0, &msg) != ATOM_OK) { ATOMLOG (_STR("Error filling queue\n")); failures++; } } /* Create a test thread that will block because the queue is full */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 2\n")); failures++; } else { /* * We have created and filled a queue. We want to see that the other * thread is woken up if its queue is deleted. This is indicated * through g_result being set. */ /* Wait for the other thread to start blocking on queue1 */ if (atomTimerDelay(SYSTEM_TICKS_PER_SEC) != ATOM_OK) { ATOMLOG (_STR("Failed timer delay\n")); failures++; } else { /* The other thread will be blocking on queue1 now, delete queue1 */ if (atomQueueDelete(&queue1) != ATOM_OK) { ATOMLOG (_STR("Failed queue1 delete\n")); failures++; } else { /* Queue1 deleted. The thread should now wake up and set g_result. */ atomTimerDelay (SYSTEM_TICKS_PER_SEC); if (g_result == 0) { ATOMLOG (_STR("Notify fail\n")); failures++; } else { /* Success */ } } } } } /* 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; }
int main ( void ) { int8_t status; sei(); SerialInit(MYUBRR); InitWatch(); /** * Reuse part of the idle thread's stack for the stack required * during this startup function. */ SP = (int)&idle_thread_stack[(IDLE_STACK_SIZE_BYTES/2) - 1]; /** * Note: to protect OS structures and data during initialisation, * interrupts must remain disabled until the first thread * has been restored. They are reenabled at the very end of * the first thread restore, at which point it is safe for a * reschedule to take place. */ /** * Initialise the OS before creating our threads. * * Note that we cannot enable stack-checking on the idle thread on * this platform because we are already using part of the idle * thread's stack now as our startup stack. Prefilling for stack * checking would overwrite our current stack. * * If you are not reusing the idle thread's stack during startup then * you are free to enable stack-checking here. */ status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, FALSE); if (status == ATOM_OK) { /* Enable the system tick timer */ avrInitSystemTickTimer(); /* Create the main thread */ status = atomThreadCreate(&main_tcb, MAIN_THREAD_PRIO, main_thread_func, 0, &main_thread_stack[0], MAIN_STACK_SIZE_BYTES, FALSE); if (status == ATOM_OK) { /** * Application threads successfully created. It is * now possible to start the OS. Execution will not return * from atomOSStart(), which will restore the context of * our application thread and start executing it. * * Note that interrupts are still disabled at this point. * They will be enabled as we restore and execute our first * thread in archFirstThreadRestore(). */ atomOSStart(); } } while (1) { atomTimerDelay (2 * SYSTEM_TICKS_PER_SEC); // wait 2 sec } /* There was an error starting the OS if we reach here */ return (0); }
/** * \b test_start * * Start semaphore test. * * With multiple threads blocking on a single semaphore, this test confirms that * they are woken in order when the semaphore is posted. The correct order for * waking is that the higher priority threads are woken first, followed by the * lower priority threads. Where multiple threads of the same priority are * waiting, the threads are woken in FIFO order (the order in which they started * waiting on the semaphore). * * To test this we create four threads which all wait on a single semaphore. * One pair of threads are running at high priority, with the other pair at a * lower priority: * * Thread 1: low prio thread A * Thread 2: low prio thread B * Thread 3: high prio thread A * Thread 4: high prio thread B * * The threads are forced to start blocking on the same semaphore in the * above order (the semaphore is initialised with count 0 to ensure any * threads calling atomSemGet() will block). * * We expect to see them woken up in the following order: * 3, 4, 1, 2 * * This proves the multiple blocking thread ordering in terms of both * the priority-queueing and same-priority-FIFO-queueing. * * @retval Number of failures */ uint32_t test_start (void) { int failures; int i; /* Default to zero failures */ failures = 0; /* Create sem with count zero (so that all threads will block) */ if (atomSemCreate (&sem1, 0) != ATOM_OK) { ATOMLOG (_STR("Error creating test semaphore 1\n")); failures++; } else { /* Create Thread 1 (lower priority thread A) */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); failures++; } /* Delay to ensure the thread will start blocking on the semaphore */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* Create Thread 2 (lower priority thread B) */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); failures++; } /* Delay to ensure the thread will start blocking on the semaphore */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* Create Thread 3 (higher priority thread A) */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); failures++; } /* Delay to ensure the thread will start blocking on the semaphore */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* Create Thread 4 (higher priority thread B) */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread\n")); failures++; } /* Delay to ensure the thread will start blocking on the semaphore */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* All four threads will now be blocking on sem1 */ /* * Initialise wake count, used by threads to determine * what order they were woken in. */ wake_cnt = 0; /* * Wake the four threads up in order, leaving some time between * each wake up for them to deal with global data in a * thread-safe fashion. */ for (i = 0; i < 4; i++) { /* Post semaphore to wake one of the threads up */ if (atomSemPut (&sem1) != ATOM_OK) { ATOMLOG (_STR("Post fail\n")); failures++; } /* Sleep to give the thread time to manipulate global data */ atomTimerDelay (SYSTEM_TICKS_PER_SEC / 4); } /* All four threads now woken up, check they woke in correct order */ if ((wake_order[0] != 3) || (wake_order[1] != 4) || (wake_order[2] != 1) || (wake_order[3] != 2)) { ATOMLOG (_STR("Bad order %d,%d,%d,%d\n"), wake_order[0], wake_order[1], wake_order[2], wake_order[3]); failures++; } /* Delete semaphore, test finished */ if (atomSemDelete (&sem1) != 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_start * * Start semaphore test. * * This tests usage of a semaphore for basic mutual exclusion type * operation. Note that Atomthreads has a more fully-featured real * mutex implementation in the mutex module. * * The semaphore sem1 is initialised with a count of 1. Whichever * thread holds this semaphore can then modify the global variable * "shared_data". * * The main thread first takes the "mutex" sem1, then creates a * second thread. The second thread should block on the sem1 mutex * until the main thread releases it. The test checks that the * global "shared_data" is not modified by the second thread * until the main thread releases the mutex. * * @retval Number of failures */ uint32_t test_start (void) { int failures; int i; /* Default to zero failures */ failures = 0; /* Create sem with count one for mutex purposes */ if (atomSemCreate (&sem1, 1) != ATOM_OK) { ATOMLOG (_STR("Error creating test semaphore 1\n")); failures++; } else { /* Initialise the shared_data to zero */ shared_data = 0; /* Take the mutex to ensure only this thread can modify shared_data */ if (atomSemGet (&sem1, 0) != ATOM_OK) { ATOMLOG (_STR("Error taking mutex\n")); failures++; } /* Create second thread */ 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\n")); failures++; } /* * The second thread has now been created and should block on * the "mutex" sem1 (which now has count zero) until we release * it. We wait a while and check that shared_data has not been * modified. */ for (i = 0; i < 4; i++) { /* * Sleep for a while to give the second thread a chance to * modify shared_data, thought it shouldn't until we * release the mutex. */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* Check shared data. The second thread always sets it to one. */ if (shared_data != 0) { ATOMLOG (_STR("Shared data modified\n")); failures++; break; } } /* Check successful so far */ if (failures == 0) { /* * Release the mutex, which will allow the second thread to * wake and start modifying shared_data. */ if (atomSemPut (&sem1) != ATOM_OK) { ATOMLOG (_STR("Failed release\n")); failures++; } /* * Wait a little while then check that shared_data has * been modified. */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); if (shared_data != 1) { ATOMLOG (_STR("Expected modify\n")); failures++; } /* * Release and take the mutex again a few times to ensure * that the mutex continues to protect shared_data. */ for (i = 0; i < 4; i++) { /* * Take the mutex again, to prevent second thread accessing * shared_data. */ if (atomSemGet (&sem1, SYSTEM_TICKS_PER_SEC) != ATOM_OK) { ATOMLOG (_STR("Retake %d\n"), i); failures++; break; } else { /* * Set shared_data to 0 and wait to ensure that the * second thread doesn't modify it while we have the * mutex again. */ shared_data = 0; /* Wait a while to give second thread potential to run */ atomTimerDelay(SYSTEM_TICKS_PER_SEC/4); /* * Check that shared_data has not been modified while we * own the mutex. */ if (shared_data != 0) { /* Thread is still modifying the data */ ATOMLOG (_STR("Still modifying\n")); failures++; break; } /* * Release the mutex, which will allow the second thread to * wake and start modifying shared_data again. */ if (atomSemPut (&sem1) != ATOM_OK) { ATOMLOG (_STR("Failed release\n")); failures++; } } } } /* Delete semaphore, test finished */ if (atomSemDelete (&sem1) != 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_start * * Start mutex test. * * This tests timeouts on a mutex. We make a thread block with timeout * on a mutex, and test that sufficient time has actually passed as * was requested by the timeout parameter. * * The main thread creates a second thread which will immediately take * ownership of the mutex. The test checks that the correct timeout * occurs when the first thread blocks on the mutex which is already * owned (by the second thread). * * @retval Number of failures */ uint32_t test_start (void) { int failures; uint32_t start_time, end_time; /* Default to zero failures */ failures = 0; /* Create mutex */ if (atomMutexCreate (&mutex1) != ATOM_OK) { ATOMLOG (_STR("Error creating mutex\n")); failures++; } else { /* Initialise the shared_data to zero */ shared_data = 0; /* Create second thread */ 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\n")); failures++; } /* * The second thread has now been created and should take ownership * of the mutex. We wait a while and check that shared_data has been * modified, which proves to us that the thread has taken the mutex. */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); if (shared_data != 1) { ATOMLOG (_STR("Shared data unmodified\n")); failures++; } /* Check successful so far */ if (failures == 0) { /* Take note of the start time */ start_time = atomTimeGet(); /* Block on the mutex with two second timeout */ if (atomMutexGet (&mutex1, 2 * SYSTEM_TICKS_PER_SEC) != ATOM_TIMEOUT) { ATOMLOG (_STR("Failed get\n")); failures++; } /* Take note of the end time */ end_time = atomTimeGet(); /* Now check that two seconds have passed */ if ((end_time < (start_time + (2 * SYSTEM_TICKS_PER_SEC))) || (end_time > (start_time + (2 * SYSTEM_TICKS_PER_SEC) + 1))) { ATOMLOG (_STR("Bad time\n")); failures++; } } /* Delete mutex, test finished */ if (atomMutexDelete (&mutex1) != 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_start * * Start queue test. * * This test verifies the queue deletion API, by deleting a queue * on which multiple threads are blocking, and checking that all three * are woken up with an appropriate error code. * * @retval Number of failures */ uint32_t test_start (void) { int failures; int i; /* Default to zero failures */ failures = 0; /* Initialise pass status for all three threads to FALSE */ for (i = 0; i < 3; i++) { pass_flag[i] = FALSE; } /* Test wakeup of three threads on queue deletion */ if (atomQueueCreate (&queue1, &queue1_storage[0], sizeof(queue1_storage[0]), QUEUE_ENTRIES) != ATOM_OK) { ATOMLOG (_STR("Error creating Q\n")); failures++; } else { /* The queue is empty so all three test threads will block */ /* Create test thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 1\n")); failures++; } /* Create test thread 2 */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 1, &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 2\n")); failures++; } /* Create test thread 3 */ else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 2, &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ ATOMLOG (_STR("Error creating test thread 3\n")); failures++; } /* Test threads now created */ else { /* Wait a while for threads to start blocking on queue1 */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* Delete queue1 now that all three threads should be blocking */ if (atomQueueDelete (&queue1) != ATOM_OK) { ATOMLOG (_STR("Delete fail\n")); failures++; } else { /* Wait a while for all three threads to wake up */ atomTimerDelay (SYSTEM_TICKS_PER_SEC/4); /* Check that all three threads have passed */ if ((pass_flag[0] != TRUE) || (pass_flag[1] != TRUE) || (pass_flag[2] != TRUE)) { ATOMLOG (_STR("Thread fail\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 usart_app_init * * Initialize USART device. * * @param[in] None * * @return None */ void usart_app_init(void) { static const gpio_map_t USART_GPIO_MAP = { {ONBOARD_USART_RX_PIN, ONBOARD_USART_RX_FUNCTION}, {ONBOARD_USART_TX_PIN, ONBOARD_USART_TX_FUNCTION} }; // USART options. static const usart_options_t USART_OPTIONS = { .baudrate = 115200, .charlength = 8, .paritytype = USART_NO_PARITY, .stopbits = USART_1_STOPBIT, .channelmode = USART_NORMAL_CHMODE }; // Assign GPIO to USART. gpio_enable_module(USART_GPIO_MAP, sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0])); // Initialize USART in RS232 mode. usart_init_rs232(ONBOARD_USART, &USART_OPTIONS, PBA_HZ); // Hello world! usart_write_line(ONBOARD_USART, "\nHello, this is AT32AP7000 saying hello!\n"); } /** * \b main_thread_func * * Entry point for main application thread. * * This is the first thread that will be executed when the OS is started. * * @param[in] data Unused (optional thread entry parameter) * * @return None */ static void main_thread_func (uint32_t data) { uint32_t test_status; int sleep_ticks; /* Initialise UART */ usart_app_init(); test_status = test_start(); /* Check main thread stack usage (if enabled) */ #ifdef ATOM_STACK_CHECKING if (test_status == 0) { uint32_t used_bytes, free_bytes; /* Check idle thread stack usage */ if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK) { /* Check the thread did not use up to the end of stack */ if (free_bytes == 0) { test_status++; } } } #endif /* Flash LED once per second if passed, very quickly if failed */ sleep_ticks = (test_status == 0) ? SYSTEM_TICKS_PER_SEC : (SYSTEM_TICKS_PER_SEC/8); /* Test finished, flash slowly for pass, fast for fail */ while (1) { /* Sleep then toggle LED again */ atomTimerDelay (sleep_ticks); } }