原始版本

This commit is contained in:
冯佳
2025-06-19 21:56:46 +08:00
parent fe98e5f010
commit a4841450cf
4152 changed files with 1910684 additions and 0 deletions

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-02-10 Bernard first version
* 2020-04-12 Jianjia Ma add msh cmd
*/
#include <rtthread.h>
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
void list_dir(const char* path)
{
char * fullpath = RT_NULL;
DIR *dir;
dir = opendir(path);
if (dir != RT_NULL)
{
struct dirent* dirent;
struct stat s;
fullpath = rt_malloc(256);
if (fullpath == RT_NULL)
{
closedir(dir);
rt_kprintf("no memory\n");
return;
}
do
{
dirent = readdir(dir);
if (dirent == RT_NULL) break;
rt_memset(&s, 0, sizeof(struct stat));
/* build full path for each file */
rt_sprintf(fullpath, "%s/%s", path, dirent->d_name);
stat(fullpath, &s);
if ( s.st_mode & S_IFDIR )
{
rt_kprintf("%s\t\t<DIR>\n", dirent->d_name);
}
else
{
rt_kprintf("%s\t\t%lu\n", dirent->d_name, s.st_size);
}
} while (dirent != RT_NULL);
closedir(dir);
}
else
{
rt_kprintf("open %s directory failed\n", path);
}
if (RT_NULL != fullpath)
{
rt_free(fullpath);
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(list_dir, list directory);
static void cmd_list_dir(int argc, char *argv[])
{
char* filename;
if(argc == 2)
{
filename = argv[1];
}
else
{
rt_kprintf("Usage: list_dir [file_path]\n");
return;
}
list_dir(filename);
}
MSH_CMD_EXPORT_ALIAS(cmd_list_dir, list_dir, list directory);
#endif /* RT_USING_FINSH */

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-02-10 Bernard first version
* 2020-04-12 Jianjia Ma add msh cmd
*/
#include <rtthread.h>
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
void readspeed(const char* filename, int block_size)
{
int fd;
char *buff_ptr;
rt_size_t total_length;
rt_tick_t tick;
fd = open(filename, 0, O_RDONLY);
if (fd < 0)
{
rt_kprintf("open file:%s failed\n", filename);
return;
}
buff_ptr = rt_malloc(block_size);
if (buff_ptr == RT_NULL)
{
rt_kprintf("no memory\n");
close(fd);
return;
}
tick = rt_tick_get();
total_length = 0;
while (1)
{
int length;
length = read(fd, buff_ptr, block_size);
if (length <= 0) break;
total_length += length;
}
tick = rt_tick_get() - tick;
/* close file and release memory */
close(fd);
rt_free(buff_ptr);
/* calculate read speed */
rt_kprintf("File read speed: %d byte/s\n", total_length /tick * RT_TICK_PER_SECOND);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(readspeed, perform file read test);
static void cmd_readspeed(int argc, char *argv[])
{
char* filename;
int block_size;
if(argc == 3)
{
filename = argv[1];
block_size = atoi(argv[2]);
}
else if(argc == 2)
{
filename = argv[1];
block_size = 512;
}
else
{
rt_kprintf("Usage:\nreadspeed [file_path] [block_size]\n");
rt_kprintf("readspeed [file_path] with default block size 512\n");
return;
}
readspeed(filename, block_size);
}
MSH_CMD_EXPORT_ALIAS(cmd_readspeed, readspeed, test file system read speed);
#endif /* RT_USING_FINSH */

View File

@ -0,0 +1,170 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-02-10 Bernard first version
* 2020-04-12 Jianjia Ma add msh cmd
*/
#include <rtthread.h>
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#define TEST_DATA_LEN 120
/* file read write test */
void readwrite(const char* filename)
{
int fd;
int index, length;
char* test_data;
char* buffer;
int block_size = TEST_DATA_LEN;
/* open with write only & create */
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
if (fd < 0)
{
rt_kprintf("open file for write failed\n");
return;
}
test_data = rt_malloc(block_size);
if (test_data == RT_NULL)
{
rt_kprintf("no memory\n");
close(fd);
return;
}
buffer = rt_malloc(block_size);
if (buffer == RT_NULL)
{
rt_kprintf("no memory\n");
close(fd);
rt_free(test_data);
return;
}
/* prepare some data */
for (index = 0; index < block_size; index ++)
{
test_data[index] = index + 27;
}
/* write to file */
length = write(fd, test_data, block_size);
if (length != block_size)
{
rt_kprintf("write data failed\n");
close(fd);
goto __exit;
}
/* close file */
close(fd);
/* reopen the file with append to the end */
fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0);
if (fd < 0)
{
rt_kprintf("open file for append write failed\n");
goto __exit;;
}
length = write(fd, test_data, block_size);
if (length != block_size)
{
rt_kprintf("append write data failed\n");
close(fd);
goto __exit;
}
/* close the file */
close(fd);
/* open the file for data validation. */
fd = open(filename, O_RDONLY, 0);
if (fd < 0)
{
rt_kprintf("check: open file for read failed\n");
goto __exit;
}
/* read the data (should be the data written by the first time ) */
length = read(fd, buffer, block_size);
if (length != block_size)
{
rt_kprintf("check: read file failed\n");
close(fd);
goto __exit;
}
/* validate */
for (index = 0; index < block_size; index ++)
{
if (test_data[index] != buffer[index])
{
rt_kprintf("check: check data failed at %d\n", index);
close(fd);
goto __exit;
}
}
/* read the data (should be the second time data) */
length = read(fd, buffer, block_size);
if (length != block_size)
{
rt_kprintf("check: read file failed\n");
close(fd);
goto __exit;
}
/* validate */
for (index = 0; index < block_size; index ++)
{
if (test_data[index] != buffer[index])
{
rt_kprintf("check: check data failed at %d\n", index);
close(fd);
goto __exit;
}
}
/* close the file */
close(fd);
/* print result */
rt_kprintf("read/write test successful!\n");
__exit:
rt_free(test_data);
rt_free(buffer);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
/* export to finsh */
FINSH_FUNCTION_EXPORT(readwrite, perform file read and write test);
static void cmd_readwrite(int argc, char *argv[])
{
char* filename;
if(argc == 2)
{
filename = argv[1];
}
else
{
rt_kprintf("Usage: readwrite [file_path]\n");
return;
}
readwrite(filename);
}
MSH_CMD_EXPORT_ALIAS(cmd_readwrite, readwrite, perform file read and write test);
#endif /* RT_USING_FINSH */

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-06-02 Bernard first version
* 2020-04-12 Jianjia Ma add msh cmd
*/
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
void seekdir_test(void)
{
DIR * dirp;
long save3 = 0;
int i = 0;
struct dirent *dp;
dirp = opendir ("/");
save3 = telldir(dirp);
for (dp = readdir(dirp); dp != RT_NULL; dp = readdir(dirp))
{
rt_kprintf("direntry: %s\n", dp->d_name);
/* save the pointer of the third directory */
if (i++ == 3)
{
save3 = telldir(dirp);
}
}
/* get back to the third directory */
seekdir (dirp, save3);
rt_kprintf("seek dientry to: %d\n", save3);
for (dp = readdir(dirp); dp != RT_NULL; dp = readdir(dirp))
{
rt_kprintf("direntry: %s\n", dp->d_name);
}
/* close the directory */
closedir (dirp);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(seekdir_test, perform directory seek test);
MSH_CMD_EXPORT(seekdir_test, perform directory seek test);
#endif /* RT_USING_FINSH */

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-02-10 Bernard first version
* 2020-04-12 Jianjia Ma add msh cmd
*/
#include <rtthread.h>
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
void writespeed(const char* filename, int total_length, int block_size)
{
int fd, index, length;
char *buff_ptr;
rt_tick_t tick;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
if (fd < 0)
{
rt_kprintf("open file:%s failed\n", filename);
return;
}
buff_ptr = rt_malloc(block_size);
if (buff_ptr == RT_NULL)
{
rt_kprintf("no memory\n");
close(fd);
return;
}
/* prepare write data */
for (index = 0; index < block_size; index++)
{
buff_ptr[index] = index;
}
index = 0;
/* get the beginning tick */
tick = rt_tick_get();
while (index < total_length / block_size)
{
length = write(fd, buff_ptr, block_size);
if (length != block_size)
{
rt_kprintf("write failed\n");
break;
}
index ++;
}
tick = rt_tick_get() - tick;
/* close file and release memory */
close(fd);
rt_free(buff_ptr);
/* calculate write speed */
rt_kprintf("File write speed: %d byte/s\n", total_length / tick * RT_TICK_PER_SECOND);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(writespeed, perform file write test);
static void cmd_writespeed(int argc, char *argv[])
{
char* filename;
int length;
int block_size;
if(argc == 4)
{
filename = argv[1];
length = atoi(argv[2]);
block_size = atoi(argv[3]);
}
else if(argc == 2)
{
filename = argv[1];
block_size = 512;
length = 1024*1024;
}
else
{
rt_kprintf("Usage:\nwritespeed [file_path] [length] [block_size]\n");
rt_kprintf("writespeed [file_path] with default length 1MB and block size 512\n");
return;
}
writespeed(filename, length, block_size);
}
MSH_CMD_EXPORT_ALIAS(cmd_writespeed, writespeed, test file system write speed);
#endif /* RT_USING_FINSH */

View File

@ -0,0 +1,6 @@
from building import *
src = Glob('*.c')
group = DefineGroup('UTest', src, depend = ['RT_USING_NEWLIBC', 'RT_USING_PTHREADS'])
Return('group')

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <finsh.h>
#include <dirent.h>
int libc_dirent()
{
DIR * dirp;
long int save3 = 0;
long int cur;
int i = 0;
int result = 0;
struct dirent *dp;
dirp = opendir("/");
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
{
/* save position 3 (after fourth entry) */
if (i++ == 3)
save3 = telldir(dirp);
printf("%s\n", dp->d_name);
/* stop at 400 (just to make sure dirp->__offset and dirp->__size are
scrambled */
if (i == 400)
break;
}
printf("going back past 4-th entry...\n");
/* go back to saved entry */
seekdir(dirp, save3);
/* Check whether telldir equals to save3 now. */
cur = telldir(dirp);
if (cur != save3)
{
printf("seekdir (d, %ld); telldir (d) == %ld\n", save3, cur);
result = 1;
}
/* print remaining files (3-last) */
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
printf("%s\n", dp->d_name);
closedir(dirp);
return result;
}
FINSH_FUNCTION_EXPORT(libc_dirent, dirent test for libc);

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <finsh.h>
int libc_env()
{
printf("PATH=%s\n", getenv("PATH"));
putenv("foo=bar");
printf("foo=%s\n", getenv("foo"));
return 0;
}
FINSH_FUNCTION_EXPORT(libc_env, get/set_env test);

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* Creates two threads, one printing 10000 "a"s, the other printing
10000 "b"s.
Illustrates: thread creation, thread joining. */
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include "pthread.h"
static void *process(void * arg)
{
int i;
printf("Starting process %s\n", (char *)arg);
for (i = 0; i < 10000; i++)
write(1, (char *) arg, 1);
return NULL;
}
#define sucfail(r) (r != 0 ? "failed" : "succeeded")
int libc_ex1(void)
{
int pret, ret = 0;
pthread_t th_a, th_b;
void *retval;
ret += (pret = pthread_create(&th_a, NULL, process, (void *)"a"));
printf("create a %s %d\n", sucfail(pret), pret);
ret += (pret = pthread_create(&th_b, NULL, process, (void *)"b"));
printf("create b %s %d\n", sucfail(pret), pret);
ret += (pret = pthread_join(th_a, &retval));
printf("join a %s %d\n", sucfail(pret), pret);
ret += (pret = pthread_join(th_b, &retval));
printf("join b %s %d\n", sucfail(pret), pret);
return ret;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex1, example 1 for libc);

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* The classic producer-consumer example.
Illustrates mutexes and conditions.
All integers between 0 and 9999 should be printed exactly twice,
once to the right of the arrow and once to the left. */
#include <stdio.h>
#include "pthread.h"
#define BUFFER_SIZE 16
/* Circular buffer of integers. */
struct prodcons {
int buffer[BUFFER_SIZE]; /* the actual data */
pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */
int readpos, writepos; /* positions for reading and writing */
pthread_cond_t notempty; /* signaled when buffer is not empty */
pthread_cond_t notfull; /* signaled when buffer is not full */
};
/* Initialize a buffer */
static void init(struct prodcons * b)
{
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
}
/* Store an integer in the buffer */
static void put(struct prodcons * b, int data)
{
pthread_mutex_lock(&b->lock);
/* Wait until buffer is not full */
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) {
pthread_cond_wait(&b->notfull, &b->lock);
/* pthread_cond_wait reacquired b->lock before returning */
}
/* Write the data and advance write pointer */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
/* Signal that the buffer is now not empty */
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
/* Read and remove an integer from the buffer */
static int get(struct prodcons * b)
{
int data;
pthread_mutex_lock(&b->lock);
/* Wait until buffer is not empty */
while (b->writepos == b->readpos) {
pthread_cond_wait(&b->notempty, &b->lock);
}
/* Read the data and advance read pointer */
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
/* Signal that the buffer is now not full */
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}
/* A test program: one thread inserts integers from 1 to 10000,
the other reads them and prints them. */
#define OVER (-1)
struct prodcons buffer;
static void * producer(void * data)
{
int n;
for (n = 0; n < 10000; n++) {
printf("%d --->\n", n);
put(&buffer, n);
}
put(&buffer, OVER);
return NULL;
}
static void * consumer(void * data)
{
int d;
while (1) {
d = get(&buffer);
if (d == OVER) break;
printf("---> %d\n", d);
}
return NULL;
}
int libc_ex2(void)
{
pthread_t th_a, th_b;
void * retval;
init(&buffer);
/* Create the threads */
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);
/* Wait until producer and consumer finish. */
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);
return 0;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex2, example 2 for libc);

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* Multi-thread searching.
Illustrates: thread cancellation, cleanup handlers. */
#include <sys/errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
/* Defines the number of searching threads */
#define NUM_THREADS 5
/* Function prototypes */
void *search(void *);
void print_it(void *);
/* Global variables */
pthread_t threads[NUM_THREADS];
pthread_mutex_t lock;
int tries;
volatile int started;
int libc_ex3()
{
int i;
int pid;
/* create a number to search for */
pid = getpid();
printf("Searching for the number = %d...\n", pid);
/* Initialize the mutex lock */
pthread_mutex_init(&lock, NULL);
/* Create the searching threads */
for (started=0; started<NUM_THREADS; started++)
pthread_create(&threads[started], NULL, search, (void *)pid);
/* Wait for (join) all the searching threads */
for (i=0; i<NUM_THREADS; i++)
pthread_join(threads[i], NULL);
printf("It took %d tries to find the number.\n", tries);
/* Exit the program */
return 0;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex3, example 5 for libc);
/* This is the cleanup function that is called
when the threads are cancelled */
void print_it(void *arg)
{
int *try = (int *) arg;
pthread_t tid;
/* Get the calling thread's ID */
tid = pthread_self();
/* Print where the thread was in its search when it was cancelled */
printf("Thread %lx was canceled on its %d try.\n", tid, *try);
}
/* This is the search routine that is executed in each thread */
void *search(void *arg)
{
int num = (int) arg;
int i, j, ntries;
pthread_t tid;
/* get the calling thread ID */
tid = pthread_self();
/* use the thread ID to set the seed for the random number generator */
/* Since srand and rand are not thread-safe, serialize with lock */
/* Try to lock the mutex lock --
if locked, check to see if the thread has been cancelled
if not locked then continue */
while (pthread_mutex_trylock(&lock) == EBUSY)
pthread_testcancel();
srand((int)tid);
i = rand() & 0xFFFFFF;
pthread_mutex_unlock(&lock);
ntries = 0;
/* Set the cancellation parameters --
- Enable thread cancellation
- Defer the action of the cancellation */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
while (started < NUM_THREADS)
sched_yield ();
/* Push the cleanup routine (print_it) onto the thread
cleanup stack. This routine will be called when the
thread is cancelled. Also note that the pthread_cleanup_push
call must have a matching pthread_cleanup_pop call. The
push and pop calls MUST be at the same lexical level
within the code */
/* Pass address of `ntries' since the current value of `ntries' is not
the one we want to use in the cleanup function */
pthread_cleanup_push(print_it, (void *)&ntries);
/* Loop forever */
while (1) {
i = (i + 1) & 0xFFFFFF;
ntries++;
/* Does the random number match the target number? */
if (num == i) {
/* Try to lock the mutex lock --
if locked, check to see if the thread has been cancelled
if not locked then continue */
while (pthread_mutex_trylock(&lock) == EBUSY)
pthread_testcancel();
/* Set the global variable for the number of tries */
tries = ntries;
printf("Thread %lx found the number!\n", tid);
/* Cancel all the other threads */
for (j=0; j<NUM_THREADS; j++)
if (threads[j] != tid) pthread_cancel(threads[j]);
/* Break out of the while loop */
break;
}
/* Every 100 tries check to see if the thread has been cancelled. */
if (ntries % 100 == 0) {
pthread_testcancel();
}
}
/* The only way we can get here is when the thread breaks out
of the while loop. In this case the thread that makes it here
has found the number we are looking for and does not need to run
the thread cleanup function. This is why the pthread_cleanup_pop
function is called with a 0 argument; this will pop the cleanup
function off the stack without executing it */
pthread_cleanup_pop(0);
return((void *)0);
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* Making a library function that uses static variables thread-safe.
Illustrates: thread-specific data, pthread_once(). */
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
/* This is a typical example of a library function that uses
static variables to accumulate results between calls.
Here, it just returns the concatenation of all string arguments
that were given to it. */
#if 0
char * str_accumulate(char * s)
{
static char accu[1024] = { 0 };
strcat(accu, s);
return accu;
}
#endif
/* Of course, this cannot be used in a multi-threaded program
because all threads store "accu" at the same location.
So, we'll use thread-specific data to have a different "accu"
for each thread. */
/* Key identifying the thread-specific data */
static pthread_key_t str_key;
/* "Once" variable ensuring that the key for str_alloc will be allocated
exactly once. */
static pthread_once_t str_alloc_key_once = PTHREAD_ONCE_INIT;
/* Forward functions */
static void str_alloc_key(void);
static void str_alloc_destroy_accu(void * accu);
/* Thread-safe version of str_accumulate */
char * str_accumulate(const char * s)
{
char * accu;
/* Make sure the key is allocated */
pthread_once(&str_alloc_key_once, str_alloc_key);
/* Get the thread-specific data associated with the key */
accu = (char *) pthread_getspecific(str_key);
/* It's initially NULL, meaning that we must allocate the buffer first. */
if (accu == NULL) {
accu = (char *)malloc(1024);
if (accu == NULL) return NULL;
accu[0] = 0;
/* Store the buffer pointer in the thread-specific data. */
pthread_setspecific(str_key, (void *) accu);
printf("Thread %lx: allocating buffer at %p\n", pthread_self(), accu);
}
/* Now we can use accu just as in the non thread-safe code. */
strcat(accu, s);
return accu;
}
/* Function to allocate the key for str_alloc thread-specific data. */
static void str_alloc_key(void)
{
pthread_key_create(&str_key, str_alloc_destroy_accu);
printf("Thread %lx: allocated key %d\n", pthread_self(), str_key);
}
/* Function to free the buffer when the thread exits. */
/* Called only when the thread-specific data is not NULL. */
static void str_alloc_destroy_accu(void * accu)
{
printf("Thread %lx: freeing buffer at %p\n", pthread_self(), accu);
free(accu);
}
/* Test program */
static void *process(void * arg)
{
char *res;
res = str_accumulate("Result of ");
res = str_accumulate((char *) arg);
res = str_accumulate(" thread");
printf("Thread %lx: \"%s\"\n", pthread_self(), res);
return NULL;
}
int libc_ex4()
{
char * res;
pthread_t th1, th2;
// res = str_accumulate("Result of ");
pthread_create(&th1, NULL, process, (void *) "first");
pthread_create(&th2, NULL, process, (void *) "second");
// res = str_accumulate("initial thread");
printf("Thread %lx: \"%s\"\n", pthread_self(), res);
pthread_join(th1, NULL);
pthread_join(th2, NULL);
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex4, example 4 for libc);

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* The classic producer-consumer example, implemented with semaphores.
All integers between 0 and 9999 should be printed exactly twice,
once to the right of the arrow and once to the left. */
#include <stdio.h>
#include "pthread.h"
#include "semaphore.h"
#define BUFFER_SIZE 16
/* Circular buffer of integers. */
struct prodcons {
int buffer[BUFFER_SIZE]; /* the actual data */
int readpos, writepos; /* positions for reading and writing */
sem_t sem_read; /* number of elements available for reading */
sem_t sem_write; /* number of locations available for writing */
};
/* Initialize a buffer */
void init(struct prodcons * b)
{
sem_init(&b->sem_write, 0, BUFFER_SIZE - 1);
sem_init(&b->sem_read, 0, 0);
b->readpos = 0;
b->writepos = 0;
}
/* Store an integer in the buffer */
void put(struct prodcons * b, int data)
{
/* Wait until buffer is not full */
sem_wait(&b->sem_write);
/* Write the data and advance write pointer */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
/* Signal that the buffer contains one more element for reading */
sem_post(&b->sem_read);
}
/* Read and remove an integer from the buffer */
int get(struct prodcons * b)
{
int data;
/* Wait until buffer is not empty */
sem_wait(&b->sem_read);
/* Read the data and advance read pointer */
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
/* Signal that the buffer has now one more location for writing */
sem_post(&b->sem_write);
return data;
}
/* A test program: one thread inserts integers from 1 to 10000,
the other reads them and prints them. */
#define OVER (-1)
struct prodcons buffer;
static void *producer(void * data)
{
int n;
for (n = 0; n < 10000; n++) {
printf("%d --->\n", n);
put(&buffer, n);
}
put(&buffer, OVER);
return NULL;
}
static void *consumer(void * data)
{
int d;
while (1) {
d = get(&buffer);
if (d == OVER) break;
printf("---> %d\n", d);
}
return NULL;
}
int libc_ex5(void)
{
pthread_t th_a, th_b;
void * retval;
init(&buffer);
/* Create the threads */
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);
/* Wait until producer and consumer finish. */
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);
return 0;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex5, example 5 for libc);

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <sys/errno.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define usleep rt_thread_delay
static void *test_thread(void *v_param) {
return NULL;
}
int libc_ex6(void) {
unsigned long count;
setvbuf(stdout, NULL, _IONBF, 0);
for (count = 0; count < 2000; ++count) {
pthread_t thread;
int status;
status = pthread_create(&thread, NULL, test_thread, NULL);
if (status != 0) {
printf("status = %d, count = %lu: %s\n", status, count, strerror(
errno));
return 1;
} else {
printf("count = %lu\n", count);
}
/* pthread_detach (thread); */
pthread_join(thread, NULL);
usleep(10);
}
return 0;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex6, example 6 for libc);

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* ex7
*
* Test case that illustrates a timed wait on a condition variable.
*/
#include <sys/errno.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#define usleep rt_thread_delay
/* Our event variable using a condition variable contruct. */
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int flag;
} event_t;
/* Global event to signal main thread the timeout of the child thread. */
event_t main_event;
static void *test_thread(void *ms_param) {
int status = 0;
event_t foo;
struct timespec time;
struct timeval now;
long ms = (long) ms_param;
/* initialize cond var */
pthread_cond_init(&foo.cond, NULL);
pthread_mutex_init(&foo.mutex, NULL);
foo.flag = 0;
/* set the time out value */
printf("waiting %ld ms ...\n", ms);
gettimeofday(&now, NULL);
time.tv_sec = now.tv_sec + ms / 1000 + (now.tv_usec + (ms % 1000) * 1000)
/ 1000000;
time.tv_nsec = ((now.tv_usec + (ms % 1000) * 1000) % 1000000) * 1000;
/* Just use this to test the time out. The cond var is never signaled. */
pthread_mutex_lock(&foo.mutex);
while (foo.flag == 0 && status != ETIMEDOUT) {
status = pthread_cond_timedwait(&foo.cond, &foo.mutex, &time);
}
pthread_mutex_unlock(&foo.mutex);
/* post the main event */
pthread_mutex_lock(&main_event.mutex);
main_event.flag = 1;
pthread_cond_signal(&main_event.cond);
pthread_mutex_unlock(&main_event.mutex);
/* that's it, bye */
return (void*) status;
}
int libc_ex7(void) {
unsigned long count;
setvbuf(stdout, NULL, _IONBF, 0);
/* initialize main event cond var */
pthread_cond_init(&main_event.cond, NULL);
pthread_mutex_init(&main_event.mutex, NULL);
main_event.flag = 0;
for (count = 0; count < 20; ++count) {
pthread_t thread;
int status;
/* pass down the milli-second timeout in the void* param */
status = pthread_create(&thread, NULL, test_thread, (void*) (count
* 100));
if (status != 0) {
printf("status = %d, count = %lu: %s\n", status, count, strerror(
errno));
return 1;
} else {
/* wait for the event posted by the child thread */
pthread_mutex_lock(&main_event.mutex);
while (main_event.flag == 0) {
pthread_cond_wait(&main_event.cond, &main_event.mutex);
}
main_event.flag = 0;
pthread_mutex_unlock(&main_event.mutex);
printf("count = %lu\n", count);
}
usleep(10);
}
return 0;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_ex7, example 7 for libc);

View File

@ -0,0 +1,520 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <finsh.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
const char* text = "this is a test string\n";
void libc_fstat()
{
int fd;
struct stat s;
fd = open("/tmp/tt.txt", O_WRONLY | O_CREAT, 0);
if (fd < 0)
{
printf("open failed\n");
return;
}
write(fd, text, strlen(text) + 1);
printf("begin: %d\n", lseek(fd, 0, SEEK_SET));
printf("end: %d\n", lseek(fd, 0, SEEK_END));
printf("fstat result: %d\n", fstat(fd, &s));
close(fd);
}
FINSH_FUNCTION_EXPORT(libc_fstat, fstat test for libc);
void libc_lseek()
{
int fd;
fd = open("/tmp/tt.txt", O_WRONLY | O_CREAT, 0);
if (fd < 0)
{
printf("open failed\n");
return;
}
write(fd, text, strlen(text) + 1);
printf("begin: %d\n", lseek(fd, 0, SEEK_SET));
printf("end: %d\n", lseek(fd, 0, SEEK_END));
close(fd);
}
FINSH_FUNCTION_EXPORT(libc_lseek, lseek test for libc);
void sleep(int tick)
{
rt_thread_delay(tick);
}
int libc_fseek(void)
{
const char *tmpdir;
char *fname;
int fd;
FILE *fp;
const char outstr[] = "hello world!\n";
char strbuf[sizeof outstr];
char buf[200];
struct stat st1;
struct stat st2;
int result = 0;
tmpdir = getenv("TMPDIR");
if (tmpdir == NULL || tmpdir[0] == '\0')
tmpdir = "/tmp";
asprintf(&fname, "%s/tst-fseek.XXXXXX", tmpdir);
if (fname == NULL)
{
fprintf(stderr, "cannot generate name for temporary file: %s\n",
strerror(errno));
return 1;
}
/* Create a temporary file. */
fd = mkstemp(fname);
if (fd == -1)
{
fprintf(stderr, "cannot open temporary file: %s\n", strerror(errno));
return 1;
}
fp = fdopen(fd, "w+");
if (fp == NULL)
{
fprintf(stderr, "cannot get FILE for temporary file: %s\n", strerror(
errno));
return 1;
}
setbuffer(fp, strbuf, sizeof(outstr) - 1);
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: write error\n", __LINE__);
result = 1;
goto out;
}
/* The EOF flag must be reset. */
if (fgetc(fp) != EOF)
{
printf("%d: managed to read at end of file\n", __LINE__);
result = 1;
}
else if (!feof(fp))
{
printf("%d: EOF flag not set\n", __LINE__);
result = 1;
}
if (fseek(fp, 0, SEEK_CUR) != 0)
{
printf("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__);
result = 1;
}
else if (feof(fp))
{
printf("%d: fseek() didn't reset EOF flag\n", __LINE__);
result = 1;
}
/* Do the same for fseeko(). */
if (fgetc(fp) != EOF)
{
printf("%d: managed to read at end of file\n", __LINE__);
result = 1;
}
else if (!feof(fp))
{
printf("%d: EOF flag not set\n", __LINE__);
result = 1;
}
if (fseeko(fp, 0, SEEK_CUR) != 0)
{
printf("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__);
result = 1;
}
else if (feof(fp))
{
printf("%d: fseek() didn't reset EOF flag\n", __LINE__);
result = 1;
}
/* Go back to the beginning of the file: absolute. */
if (fseek(fp, 0, SEEK_SET) != 0)
{
printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
result = 1;
}
else if (fflush(fp) != 0)
{
printf("%d: fflush() failed\n", __LINE__);
result = 1;
}
else if (lseek(fd, 0, SEEK_CUR) != 0)
{
int pos = lseek(fd, 0, SEEK_CUR);
printf("%d: lseek() returned different position, pos %d\n", __LINE__,
pos);
result = 1;
}
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: fread() failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
{
printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
result = 1;
}
/* Now with fseeko. */
if (fseeko(fp, 0, SEEK_SET) != 0)
{
printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
result = 1;
}
else if (fflush(fp) != 0)
{
printf("%d: fflush() failed\n", __LINE__);
result = 1;
}
else if (lseek(fd, 0, SEEK_CUR) != 0)
{
printf("%d: lseek() returned different position\n", __LINE__);
result = 1;
}
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: fread() failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
{
printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
result = 1;
}
/* Go back to the beginning of the file: relative. */
if (fseek(fp, -((int) sizeof(outstr) - 1), SEEK_CUR) != 0)
{
printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
result = 1;
}
else if (fflush(fp) != 0)
{
printf("%d: fflush() failed\n", __LINE__);
result = 1;
}
else if (lseek(fd, 0, SEEK_CUR) != 0)
{
printf("%d: lseek() returned different position\n", __LINE__);
result = 1;
}
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: fread() failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
{
printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
result = 1;
}
/* Now with fseeko. */
if (fseeko(fp, -((int) sizeof(outstr) - 1), SEEK_CUR) != 0)
{
printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
result = 1;
}
else if (fflush(fp) != 0)
{
printf("%d: fflush() failed\n", __LINE__);
result = 1;
}
else if (lseek(fd, 0, SEEK_CUR) != 0)
{
printf("%d: lseek() returned different position\n", __LINE__);
result = 1;
}
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: fread() failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
{
printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
result = 1;
}
/* Go back to the beginning of the file: from the end. */
if (fseek(fp, -((int) sizeof(outstr) - 1), SEEK_END) != 0)
{
printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
result = 1;
}
else if (fflush(fp) != 0)
{
printf("%d: fflush() failed\n", __LINE__);
result = 1;
}
else if (lseek(fd, 0, SEEK_CUR) != 0)
{
printf("%d: lseek() returned different position\n", __LINE__);
result = 1;
}
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: fread() failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
{
printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
result = 1;
}
/* Now with fseeko. */
if (fseeko(fp, -((int) sizeof(outstr) - 1), SEEK_END) != 0)
{
printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
result = 1;
}
else if (fflush(fp) != 0)
{
printf("%d: fflush() failed\n", __LINE__);
result = 1;
}
else if (lseek(fd, 0, SEEK_CUR) != 0)
{
printf("%d: lseek() returned different position\n", __LINE__);
result = 1;
}
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: fread() failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
{
printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
result = 1;
}
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: write error 2\n", __LINE__);
result = 1;
goto out;
}
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: write error 3\n", __LINE__);
result = 1;
goto out;
}
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: write error 4\n", __LINE__);
result = 1;
goto out;
}
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
{
printf("%d: write error 5\n", __LINE__);
result = 1;
goto out;
}
if (fputc('1', fp) == EOF || fputc('2', fp) == EOF)
{
printf("%d: cannot add characters at the end\n", __LINE__);
result = 1;
goto out;
}
/* Check the access time. */
if (fstat(fd, &st1) < 0)
{
printf("%d: fstat64() before fseeko() failed\n\n", __LINE__);
result = 1;
}
else
{
sleep(1);
if (fseek(fp, -(2 + 2 * (sizeof(outstr) - 1)), SEEK_CUR) != 0)
{
printf("%d: fseek() after write characters failed\n", __LINE__);
result = 1;
goto out;
}
else
{
time_t t;
/* Make sure the timestamp actually can be different. */
sleep(1);
t = time(NULL);
if (fstat(fd, &st2) < 0)
{
printf("%d: fstat64() after fseeko() failed\n\n", __LINE__);
result = 1;
}
if (st1.st_ctime >= t)
{
printf("%d: st_ctime not updated\n", __LINE__);
result = 1;
}
if (st1.st_mtime >= t)
{
printf("%d: st_mtime not updated\n", __LINE__);
result = 1;
}
if (st1.st_ctime >= st2.st_ctime)
{
printf("%d: st_ctime not changed\n", __LINE__);
result = 1;
}
if (st1.st_mtime >= st2.st_mtime)
{
printf("%d: st_mtime not changed\n", __LINE__);
result = 1;
}
}
}
if (fread(buf, 1, 2 + 2 * (sizeof(outstr) - 1), fp) != 2 + 2
* (sizeof(outstr) - 1))
{
printf("%d: reading 2 records plus bits failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0 || memcmp(
&buf[sizeof(outstr) - 1], outstr, sizeof(outstr) - 1) != 0 || buf[2
* (sizeof(outstr) - 1)] != '1' || buf[2 * (sizeof(outstr) - 1) + 1]
!= '2')
{
printf("%d: reading records failed\n", __LINE__);
result = 1;
}
else if (ungetc('9', fp) == EOF)
{
printf("%d: ungetc() failed\n", __LINE__);
result = 1;
}
else if (fseek(fp, -(2 + 2 * (sizeof(outstr) - 1)), SEEK_END) != 0)
{
printf("%d: fseek after ungetc failed\n", __LINE__);
result = 1;
}
else if (fread(buf, 1, 2 + 2 * (sizeof(outstr) - 1), fp) != 2 + 2
* (sizeof(outstr) - 1))
{
printf("%d: reading 2 records plus bits failed\n", __LINE__);
result = 1;
}
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0 || memcmp(
&buf[sizeof(outstr) - 1], outstr, sizeof(outstr) - 1) != 0 || buf[2
* (sizeof(outstr) - 1)] != '1')
{
printf("%d: reading records for the second time failed\n", __LINE__);
result = 1;
}
else if (buf[2 * (sizeof(outstr) - 1) + 1] == '9')
{
printf("%d: unget character not ignored\n", __LINE__);
result = 1;
}
else if (buf[2 * (sizeof(outstr) - 1) + 1] != '2')
{
printf("%d: unget somehow changed character\n", __LINE__);
result = 1;
}
fclose(fp);
fp = fopen(fname, "r");
if (fp == NULL)
{
printf("%d: fopen() failed\n\n", __LINE__);
result = 1;
}
else if (fstat(fileno(fp), &st1) < 0)
{
printf("%d: fstat64() before fseeko() failed\n\n", __LINE__);
result = 1;
}
else if (fseeko(fp, 0, SEEK_END) != 0)
{
printf("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__);
result = 1;
}
else if (ftello(fp) != st1.st_size)
{
printf("%d: fstat64 st_size %zd ftello %zd\n", __LINE__,
(size_t) st1.st_size, (size_t) ftello(fp));
result = 1;
}
else
printf("%d: SEEK_END works\n", __LINE__);
if (fp != NULL)
fclose(fp);
fp = fopen(fname, "r");
if (fp == NULL)
{
printf("%d: fopen() failed\n\n", __LINE__);
result = 1;
}
else if (fstat(fileno(fp), &st1) < 0)
{
printf("%d: fstat64() before fgetc() failed\n\n", __LINE__);
result = 1;
}
else if (fgetc(fp) == EOF)
{
printf("%d: fgetc() before fseeko() failed\n\n", __LINE__);
result = 1;
}
else if (fseeko(fp, 0, SEEK_END) != 0)
{
printf("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__);
result = 1;
}
else if (ftello(fp) != st1.st_size)
{
printf("%d: fstat64 st_size %zd ftello %zd\n", __LINE__,
(size_t) st1.st_size, (size_t) ftello(fp));
result = 1;
}
else
printf("%d: SEEK_END works\n", __LINE__);
if (fp != NULL)
fclose(fp);
out: unlink(fname);
return result;
}
FINSH_FUNCTION_EXPORT(libc_fseek, lseek test for libc);

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <finsh.h>
#include <sys/errno.h>
static int errors = 0;
static void merror(const char *msg)
{
++errors;
printf("Error: %s\n", msg);
}
int libc_mem(void)
{
void *p;
int save;
errno = 0;
p = malloc(-1);
save = errno;
if (p != NULL)
merror("malloc (-1) succeeded.");
if (p == NULL && save != ENOMEM)
merror("errno is not set correctly");
p = malloc(10);
if (p == NULL)
merror("malloc (10) failed.");
/* realloc (p, 0) == free (p). */
p = realloc(p, 0);
if (p != NULL)
merror("realloc (p, 0) failed.");
p = malloc(0);
if (p == NULL)
{
printf("malloc(0) returns NULL\n");
}
p = realloc(p, 0);
if (p != NULL)
merror("realloc (p, 0) failed.");
return errors != 0;
}
FINSH_FUNCTION_EXPORT(libc_mem, memory test for libc);

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <mqueue.h>
#define MQ_NAME_1 "testmsg1"
#define MQ_NAME_2 "testmsg2"
#define MSG_SIZE 128
#define MAX_MSG 3
const char *s_msg_ptr[] = {"msg test 1", "msg test 2", "msg test 3"};
char r_msg_ptr_1[MAX_MSG][MSG_SIZE];
char r_msg_ptr_2[MAX_MSG][MSG_SIZE];
pthread_t send1, send2, rev1, rev2;
int * send_1(void * mq)
{
int i;
mqd_t mq1 = *(mqd_t *)mq;
printf("Enter into send_1 \n");
for (i = 0; i < MAX_MSG; i++ ) {
if ( -1 == mq_send(mq1, s_msg_ptr[i], MSG_SIZE, i)) {
perror("mq_send doesn't return success \n");
pthread_exit((void *)1);
}
printf("[%d] send '%s' in thread send_1. \n", i+1, s_msg_ptr[i]);
}
pthread_exit((void *)0);
}
int * send_2(void * mq)
{
int i;
mqd_t mq2 = *(mqd_t *)mq;
printf("Enter into send_2 \n");
for (i = 0; i < MAX_MSG; i++ ) {
if ( -1 == mq_send(mq2, s_msg_ptr[i], MSG_SIZE, i)) {
perror("mq_send doesn't return success \n");
pthread_exit((void *)1);
}
printf("[%d] send '%s' in thread send_2. \n", i+1, s_msg_ptr[i]);
}
pthread_exit((void *)0);
}
int * receive_1(void * mq)
{
int i;
mqd_t mq1 = *(mqd_t *)mq;
printf("Enter into receive_1 \n");
for (i = 0; i< MAX_MSG; i++) {
if ( -1 == mq_receive(mq1, r_msg_ptr_1[i], MSG_SIZE, NULL) ) {
perror("mq_receive doesn't return success \n");
pthread_exit((void *)1);
}
printf("[%d] receive '%s' in thread receive_1. \n", i+1, r_msg_ptr_1[i]);
}
pthread_exit((void *)0);
}
int * receive_2(void * mq)
{
int i;
mqd_t mq2 = *(mqd_t *)mq;
printf("Enter into receive_2 \n");
for (i = 0; i< MAX_MSG; i++) {
if ( -1 == mq_receive(mq2, r_msg_ptr_2[i], MSG_SIZE, NULL) ) {
perror("mq_receive doesn't return success \n");
pthread_exit((void *)1);
}
printf("[%d] receive '%s' in thread receive_2. \n", i+1, r_msg_ptr_2[i]);
}
pthread_exit((void *)0);
}
int libc_mq()
{
mqd_t mq1 = 0, mq2 = 0;
struct mq_attr mqstat;
int oflag = O_CREAT|O_RDWR;
memset(&mqstat, 0, sizeof(mqstat));
mqstat.mq_maxmsg = MAX_MSG;
mqstat.mq_msgsize = MSG_SIZE;
mqstat.mq_flags = 0;
if( ((mqd_t) -1) == (mq1 = mq_open(MQ_NAME_1,oflag,0777, &mqstat)) ) {
printf("mq_open doesn't return success \n");
return -1;
}
if( ((mqd_t) -1) == (mq2 = mq_open(MQ_NAME_2,oflag,0777, &mqstat)) ) {
printf("mq_open doesn't return success \n");
return -1;
}
pthread_create(&send1, NULL, (void *)send_1, (void *)&mq1);
pthread_create(&send2, NULL, (void *)send_2, (void *)&mq2);
pthread_create(&rev1, NULL, (void *)receive_1, (void *)&mq1);
pthread_create(&rev2, NULL, (void *)receive_2, (void *)&mq2);
pthread_join(send1, NULL);
pthread_join(send2, NULL);
pthread_join(rev1, NULL);
pthread_join(rev2, NULL);
mq_close(mq1);
mq_close(mq2);
mq_unlink(MQ_NAME_1);
mq_unlink(MQ_NAME_2);
printf("PASSED\n");
return 0;
}
#include <finsh.h>
FINSH_FUNCTION_EXPORT(libc_mq, posix mqueue test);

View File

@ -0,0 +1,210 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <finsh.h>
char * format[] = {
"%",
"%0.",
"%.0",
"%+0.",
"%+.0",
"%.5",
"%+.5",
"%2.5",
"%22.5",
"%022.5",
"%#022.5",
"%-#022.5",
"%+#022.5",
"%-22.5",
"%+22.5",
"%--22.5",
"%++22.5",
"%+-22.5",
"%-+22.5",
"%-#022.5",
"%-#22.5",
"%-2.22",
"%+2.22",
"%-#02.22",
"%-#2.22",
"%-1.5",
"%1.5",
"%-#01.5",
"%-#1.5",
"%-#.5",
"%-#1.",
"%-#.",
NULL
};
static void
intchk (const char *fmt)
{
(void) printf("%15s :, \"", fmt);
(void) printf(fmt, 0);
(void) printf("\", \"");
(void) printf(fmt, 123);
(void) printf("\", \"");
(void) printf(fmt, -18);
(void) printf("\"\n");
}
static void
fltchk (const char *fmt)
{
(void) printf("%15s :, \"", fmt);
(void) printf(fmt, 0.0);
(void) printf("\", \"");
(void) printf(fmt, 123.0001);
(void) printf("\", \"");
(void) printf(fmt, -18.0002301);
(void) printf("\"\n");
}
int printf_test()
{
char buf[256];
int i;
printf("%s\n\n", "# vim:syntax=off:");
/* integers */
for(i=0;format[i];i++) {
strcpy(buf, format[i]);
strcat(buf, "d");
intchk(buf);
}
/* floats */
for(i=0;format[i];i++) {
strcpy(buf, format[i]);
strcat(buf, "f");
fltchk(buf);
}
/* hexa */
for(i=0;format[i];i++) {
strcpy(buf, format[i]);
strcat(buf, "x");
intchk(buf);
}
printf("#%.4x %4x#\n", 4, 88);
printf("#%4x#\n",4);
printf("#%#22.8x#\n",1234567);
printf("#%+2i#\n",18);
printf("#%i#\n",18);
printf("#%llu#\n",4294967297ULL);
printf("#%#x#\n",44444);
printf("#%-8i#\n",33);
printf("#%i#\n",18);
printf("#%d#\n",18);
printf("#%u#\n",18);
printf("#%lu#\n",18);
printf("#%li#\n",18);
printf("#%-+#06d#\n", -123);
printf("#%-+#6d#\n", -123);
printf("#%+#06d#\n", -123);
printf("#%06d#\n", -123);
printf("#%+15s#\n","ABCDEF");
/* from ncurses make_keys */
printf("{ %4d, %-*.*s },\t/* %s */\n", 139, 16, 16, "KEY_A1", "key_a1");
printf("{ %4d, %-*.*s },\t/* %s */\n", 139, 16, 2, "KEY_A1", "key_a1");
printf("{ %4d, %-*.*s },\t/* %s */\n", 139, 2, 16, "KEY_A1", "key_a1");
printf("{ %4d, %-*.*s },\t/* %s */\n", 139, 16, 0, "KEY_A1", "key_a1");
printf("{ %4d, %-*.*s },\t/* %s */\n", 139, 0, 16, "KEY_A1", "key_a1");
printf("{ %4d, %-*.*s },\t/* %s */\n", 139, 0, 0, "KEY_A1", "key_a1");
printf("{ %4d, %*.*s },\t/* %s */\n", 139, 16, 16, "KEY_A1", "key_a1");
printf("{ %4d, %*.*s },\t/* %s */\n", 139, 16, 2, "KEY_A1", "key_a1");
printf("{ %4d, %*.*s },\t/* %s */\n", 139, 2, 16, "KEY_A1", "key_a1");
printf("{ %4d, %*.*s },\t/* %s */\n", 139, 16, 0, "KEY_A1", "key_a1");
printf("{ %4d, %*.*s },\t/* %s */\n", 139, 0, 16, "KEY_A1", "key_a1");
printf("{ %4d, %*.*s },\t/* %s */\n", 139, 0, 0, "KEY_A1", "key_a1");
printf("%*.*f\n", 0, 16, 0.0);
printf("%*.*f\n", 16, 16, 0.0);
printf("%*.*f\n", 2, 2, -0.0);
printf("%*.*f\n", 20, 0, -123.123);
printf("%*.*f\n", 10, 0, +123.123);
i = printf("\"%s\"\n","A");
printf("%i\n", i);
/* from glibc's tst-printf.c */
{
char buf[20];
char buf2[512];
int i;
printf ("snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n",
snprintf (buf, sizeof (buf), "%30s", "foo"), (int) sizeof (buf),
buf);
memset(buf2,0,sizeof(buf));
i=snprintf(buf2, 256, "%.9999u", 10);
printf("%i %i\n",i,strlen(buf2));
printf ("snprintf (\"%%.999999u\", 10) == %d\n",
snprintf(buf2, sizeof(buf2), "%.999999u", 10));
}
return 0;
}
void libc_printf()
{
printf("stdout test!!\n");
fprintf(stdout, "fprintf test!!\n");
fprintf(stderr, "fprintf test!!\n");
puts("puts test!!\n");
putc('1', stderr);
putc('2', stderr);
putc('\n', stderr);
printf_test();
}
FINSH_FUNCTION_EXPORT(libc_printf, printf test in libc);
void libc_dprintf()
{
int fd;
fd = open("/dev/console", O_WRONLY, 0);
if (fd >0)
{
dprintf(fd, "fd:%d printf test!!\n", fd);
close(fd);
}
}
FINSH_FUNCTION_EXPORT(libc_dprintf, dprintf test);
void libc_fdopen()
{
int fd;
FILE* fp;
fd = open("/dev/console", O_WRONLY, 0);
if (fd >0)
{
fp = fdopen(fd, "w");
fprintf(fp, "fdopen test, fd %d!!\n", fileno(fp));
fclose(fp);
}
}
FINSH_FUNCTION_EXPORT(libc_fdopen, fdopen test);

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <finsh.h>
int libc_rand(void)
{
int i1, i2;
int j1, j2;
/* The C standard says that "If rand is called before any calls to
srand have been made, the same sequence shall be generated as
when srand is first called with a seed value of 1." */
i1 = rand();
i2 = rand();
srand(1);
j1 = rand();
j2 = rand();
if (i1 < 0 || i2 < 0 || j1 < 0 || j2 < 0)
{
puts("Test FAILED!");
}
if (j1 == i1 && j2 == i2)
{
puts("Test succeeded.");
return 0;
}
else
{
if (j1 != i1)
printf("%d != %d\n", j1, i1);
if (j2 != i2)
printf("%d != %d\n", j2, i2);
puts("Test FAILED!");
return 1;
}
}
FINSH_FUNCTION_EXPORT(libc_rand, rand test for libc);

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
static sem_t sema;
static void* other_thread()
{
printf("other_thread here!\n");
sleep(1);
while (1)
{
printf("other_thread: sem_post...\n");
if(sem_post(&sema) == -1)
printf("sem_post failed\n");
sleep(1);
}
printf("other_thread dies!\n");
pthread_exit(0);
}
static void test_thread(void* parameter)
{
pthread_t tid;
printf("main thread here!\n");
printf("sleep 5 seconds...");
sleep(5);
printf("done\n");
sem_init(&sema, 0, 0);
/* create the "other" thread */
if(pthread_create(&tid, 0, &other_thread, 0)!=0)
/* error */
printf("pthread_create OtherThread failed.\n");
else
printf("created OtherThread=%x\n", tid);
/* let the other thread run */
while (1)
{
printf("Main: sem_wait...\n");
if(sem_wait(&sema) == -1)
printf("sem_wait failed\n");
printf("Main back.\n\n");
}
pthread_exit(0);
}
#include <finsh.h>
void libc_sem()
{
rt_thread_t tid;
tid = rt_thread_create("semtest", test_thread, RT_NULL,
2048, 20, 5);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
}
FINSH_FUNCTION_EXPORT(libc_sem, posix semaphore test);

View File

@ -0,0 +1,351 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-12-06 JasonJia first version
*/
#include <rtthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#define JOINT(x,y) x##y
#define B(x) JOINT(B,x)
#define Default_baud_rate 115200
#define Default_parity 'n'
#define BUFFER_SIZE 64
struct termios_test_s
{
int baud_rate;
const char *dev;
};
static struct termios_test_s term_param;
static int _check_baud_rate(int baud_rate)
{
#define BAUD_RATE(x) \
{\
if(x==baud_rate) \
{\
rt_kprintf("%d baud rate\n",baud_rate);\
return JOINT(B,x);\
}\
}
BAUD_RATE(110);
BAUD_RATE(200);
BAUD_RATE(300);
BAUD_RATE(600);
BAUD_RATE(1200);
BAUD_RATE(1800);
BAUD_RATE(2400);
BAUD_RATE(4800);
BAUD_RATE(9600);
BAUD_RATE(19200);
BAUD_RATE(38400);
BAUD_RATE(57600);
BAUD_RATE(115200);
BAUD_RATE(230400);
BAUD_RATE(460800);
BAUD_RATE(921600);
rt_kprintf("%d is not support,use default %d value.\n",baud_rate,Default_baud_rate);
return B(Default_baud_rate);
}
int open_comm(const char *name)
{
int fd;
fd = open(name, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
if(fd == -1)
{
rt_kprintf("Open %s fail.\n",name);
return -1;
}
else
{
rt_kprintf("Open %s success,fd:%d\n",name,fd);
}
return fd;
}
void close_comm(int fd)
{
if(fd != -1)
{
close(fd);
}
}
void config_comm(int fd, int speed_baud_rate, char parity, int data_bits, int stop_bits)
{
int valid_baud_rate = 0;
struct termios new_tc;
memset(&new_tc, 0x00, sizeof(struct termios));
valid_baud_rate = _check_baud_rate(speed_baud_rate);
new_tc.c_cflag |= (CLOCAL | CREAD);//Enable in default.
/*
*Set baud rate. e.g B115200 is 115200 bauds.
*/
cfsetispeed(&new_tc, valid_baud_rate);//input speed
cfsetospeed(&new_tc, valid_baud_rate);//output speed
/*
*Set parity.
*/
switch(parity)
{
case 'n':
case 'N':
new_tc.c_cflag &= ~PARENB; //Disable parity.
break;
case 'o':
case 'O':
new_tc.c_cflag |= PARENB; //Enable parity.
new_tc.c_cflag |= PARODD; //Odd parity.
break;
case 'e':
case 'E':
new_tc.c_cflag |= PARENB; //Enable parity.
new_tc.c_cflag &= ~PARODD; //even parity.
break;
}
/*
*Set data bits.
*/
new_tc.c_cflag &= ~CSIZE;
switch(data_bits)
{
case 5:
break;
case 6:
break;
case 7:
new_tc.c_cflag |= CS7;
break;
case 8:
new_tc.c_cflag |= CS8;
break;
}
/*
*Set stop bits.
*/
(stop_bits == 2)?(new_tc.c_cflag |= CSTOPB):(new_tc.c_cflag &= ~ CSTOPB);
tcflush(fd,TCIFLUSH);
//new_tc.c_cc[VTIME] = 0;
//new_tc.c_cc[VMIN] = 1;
if( tcsetattr(fd, TCSANOW, &new_tc) != 0)
{
rt_kprintf("Set port config fail!\n");
}
}
int recv_comm(int fd, unsigned char *buffer, rt_size_t size, struct timeval *timeout)
{
struct timeval t;
int ret = 0;
rt_size_t drv_recved = 0;
int recved = 0, need = size;
int timeout_cnt = 0;
unsigned char *c = RT_NULL;
fd_set readSet;
RT_ASSERT(RT_NULL != buffer);
if(fd == -1)
{
return -1;
}
t.tv_sec = 0;
t.tv_usec = 100000;
if(RT_NULL == timeout)
{
/* Wait forever approximate, it's a large time. */
timeout_cnt = 0xffffffff;
}
else
{
timeout_cnt = (timeout->tv_sec * 1000 * 1000 + timeout->tv_usec)/(t.tv_sec * 1000 * 1000 + t.tv_usec);
}
while(1)
{
FD_ZERO(&readSet);
FD_SET(fd, &readSet);
ret = select(fd+1,&readSet,RT_NULL,RT_NULL,&t);
if(ret < 0)
{
rt_kprintf("select error %d\n",ret);
break;
}
else if(ret == 0)
{
/* timeout */
timeout_cnt--;
if(timeout_cnt == 0)
{
rt_kprintf("need %d data in timeout %d ms,but only %d recved.\n",
size,
timeout->tv_sec * 1000 + timeout->tv_usec / 1000,
recved);
recved = 0;
break;
}
}
else
{
if(FD_ISSET(fd, &readSet))
{
c = &buffer[size - need];
ioctl(fd, FIONREAD, &drv_recved);
/* check poll and ioctl */
RT_ASSERT(drv_recved != 0);
drv_recved = (drv_recved > need ? need : drv_recved);
recved = read(fd, c, drv_recved);
if(recved != drv_recved)
{
rt_kprintf("fatal error %s(%d).\n",__FUNCTION__,__LINE__);
RT_ASSERT(0);
recved = 0;
break;
}
need -= recved;
if(need)
{
continue;
}
else if (need == 0)
{
recved = size;
break;
}
else
{
rt_kprintf("fatal error %s(%d).\n",__FUNCTION__,__LINE__);
RT_ASSERT(0);
}
}
}
}
return recved;
}
int send_comm(int fd, const unsigned char *buffer, rt_size_t size)
{
RT_ASSERT(RT_NULL != buffer);
if(fd == -1)
{
return -1;
}
//serial framework does not support poll out now
write(fd, buffer, size);
return 0;
}
int flush_comm(int fd)
{
if(fd == -1)
{
return -1;
}
tcflush(fd,TCIFLUSH);
return 0;
}
void termios_test_entry(void *p)
{
int len = 0;
int fd = -1;
unsigned char *pBuf = RT_NULL;
struct termios_test_s *pTerm = (struct termios_test_s *)p;
if((fd = open_comm(pTerm->dev)) == -1)
{
rt_kprintf("Check the device name...\n");
return;
}
pBuf = (unsigned char *)rt_malloc(BUFFER_SIZE);
RT_ASSERT(pBuf != RT_NULL);
memset(pBuf, 0x00, BUFFER_SIZE);
config_comm(fd, pTerm->baud_rate, Default_parity, 8, 1);
flush_comm(fd);
rt_kprintf("Block recv 10 bytes.\n");
/* Block recv 10 bytes */
len = recv_comm(fd, pBuf, 10, RT_NULL);
rt_kprintf("Recv:%s\n", pBuf);
send_comm(fd, pBuf, len);
rt_kprintf("Termios test exit.\n");
close_comm(fd);
rt_free(pBuf);
pBuf = RT_NULL;
}
int termios_test(int argc, char **argv)
{
rt_thread_t tid;
if(argc < 2)
{
rt_kprintf("Please input device name...\n");
return -1;
}
term_param.dev = argv[1];
term_param.baud_rate = ((argc >= 3) ? atoi(argv[2]) : Default_baud_rate);
tid = rt_thread_create("termtest",
termios_test_entry, (void *)&term_param,
512, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
rt_thread_startup(tid);
return 0;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(termios_test, termtest, e.g: termtest /dev/uart4 115200);
#endif /* RT_USING_FINSH */
#endif /* RT_USING_FINSH */

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-11-17 Bernard first version
*/
#include <stdio.h>
#include <stdlib.h>
#include <finsh.h>
int speed()
{
int i;
time_t t;
printf("%d\n", time(0));
for (i = 0; i < 10000000; ++i)
t = time(0);
printf("%d\n", time(0));
return 0;
}
FINSH_FUNCTION_EXPORT(speed, speed test);

View File

@ -0,0 +1,244 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rtthread.h>
#include <sys/socket.h>
#ifdef SAL_USING_POSIX
#include <sys/select.h> // only dfs_net
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#else
#define read lwip_read
#define write lwip_write
#endif /* SAL_USING_POSIX */
#include "netdb.h"
#define MAX_SERV 32 /* Maximum number of chargen services. Don't need too many */
#define CHARGEN_THREAD_NAME "chargen"
#if RT_THREAD_PRIORITY_MAX == 32
#define CHARGEN_PRIORITY 20 /* Really low priority */
#else
#define CHARGEN_PRIORITY 200 /* Really low priority */
#endif
#define CHARGEN_THREAD_STACKSIZE 1024
struct charcb
{
struct charcb *next;
int socket;
struct sockaddr_in cliaddr;
socklen_t clilen;
char nextchar;
};
static struct charcb *charcb_list = 0;
static int do_read(struct charcb *p_charcb);
static void close_chargen(struct charcb *p_charcb);
extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
/**************************************************************
* void chargen_thread(void *arg)
*
* chargen task. This server will wait for connections on well
* known TCP port number: 19. For every connection, the server will
* write as much data as possible to the tcp port.
**************************************************************/
static void chargen_thread(void *arg)
{
int listenfd;
struct sockaddr_in chargen_saddr;
fd_set readset;
fd_set writeset;
int i, maxfdp1;
struct charcb *p_charcb;
/* First acquire our socket for listening for connections */
listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
memset(&chargen_saddr, 0, sizeof(chargen_saddr));
chargen_saddr.sin_family = AF_INET;
chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
chargen_saddr.sin_port = htons(19); // Chargen server port
if (bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
/* Put socket into listening mode */
if (listen(listenfd, MAX_SERV) == -1)
LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
/* Wait forever for network input: This could be connections or data */
for (;;)
{
maxfdp1 = listenfd + 1;
/* Determine what sockets need to be in readset */
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(listenfd, &readset);
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
{
if (maxfdp1 < p_charcb->socket + 1)
maxfdp1 = p_charcb->socket + 1;
FD_SET(p_charcb->socket, &readset);
FD_SET(p_charcb->socket, &writeset);
}
/* Wait for data or a new connection */
i = select(maxfdp1, &readset, &writeset, 0, 0);
if (i == 0) continue;
/* At least one descriptor is ready */
if (FD_ISSET(listenfd, &readset))
{
/* We have a new connection request!!! */
/* Lets create a new control block */
p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
if (p_charcb)
{
p_charcb->socket = accept(listenfd,
(struct sockaddr *) &p_charcb->cliaddr,
&p_charcb->clilen);
if (p_charcb->socket < 0)
rt_free(p_charcb);
else
{
/* Keep this tecb in our list */
p_charcb->next = charcb_list;
charcb_list = p_charcb;
p_charcb->nextchar = 0x21;
}
}
else
{
/* No memory to accept connection. Just accept and then close */
int sock;
struct sockaddr cliaddr;
socklen_t clilen;
sock = accept(listenfd, &cliaddr, &clilen);
if (sock >= 0)
closesocket(sock);
}
}
/* Go through list of connected clients and process data */
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
{
if (FD_ISSET(p_charcb->socket, &readset))
{
/* This socket is ready for reading. This could be because someone typed
* some characters or it could be because the socket is now closed. Try reading
* some data to see. */
if (do_read(p_charcb) < 0)
break;
}
if (FD_ISSET(p_charcb->socket, &writeset))
{
char line[80];
char setchar = p_charcb->nextchar;
for (i = 0; i < 59; i++)
{
line[i] = setchar;
if (++setchar == 0x7f)
setchar = 0x21;
}
line[i] = 0;
strcat(line, "\n\r");
if (write(p_charcb->socket, line, strlen(line)) < 0)
{
close_chargen(p_charcb);
break;
}
if (++p_charcb->nextchar == 0x7f)
p_charcb->nextchar = 0x21;
}
}
}
}
/**************************************************************
* void close_chargen(struct charcb *p_charcb)
*
* Close the socket and remove this charcb from the list.
**************************************************************/
static void close_chargen(struct charcb *p_charcb)
{
struct charcb *p_search_charcb;
/* Either an error or tcp connection closed on other
* end. Close here */
closesocket(p_charcb->socket);
/* Free charcb */
if (charcb_list == p_charcb)
charcb_list = p_charcb->next;
else
for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
{
if (p_search_charcb->next == p_charcb)
{
p_search_charcb->next = p_charcb->next;
break;
}
}
rt_free(p_charcb);
}
/**************************************************************
* void do_read(struct charcb *p_charcb)
*
* Socket definitely is ready for reading. Read a buffer from the socket and
* discard the data. If no data is read, then the socket is closed and the
* charcb is removed from the list and freed.
**************************************************************/
static int do_read(struct charcb *p_charcb)
{
char buffer[80];
int readcount;
/* Read some data */
readcount = read(p_charcb->socket, &buffer, 80);
if (readcount <= 0)
{
close_chargen(p_charcb);
return -1;
}
return 0;
}
void chargen_init(void)
{
rt_thread_t chargen;
chargen = rt_thread_create(CHARGEN_THREAD_NAME,
chargen_thread, RT_NULL,
CHARGEN_THREAD_STACKSIZE,
CHARGEN_PRIORITY, 5);
if (chargen != RT_NULL) rt_thread_startup(chargen);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
void chargen()
{
chargen_init();
}
FINSH_FUNCTION_EXPORT(chargen, start chargen server);
#endif

View File

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('192.168.10.110',6001))
print s.recv(1024)
for data in ['rtt_nano','rtt_thread','rtt_bsp']:
s.send(data)
print s.recv(1024)
s.send('exit')
s.close()

View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
#引入模块
import socket
import threading
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听端口:
s.bind(('192.168.10.110', 6001))
s.listen(5)
print 'Waiting for connection...'
def tcp_link(sock,addr):
print 'Accept new connection from %s:%s...' % addr
sock.send('Welcome to RT-Thread!')
while True:
data=sock.recv(1024)
time.sleep(1)
if data=='exit' or not data:
break
print data
sock.send('Hello,%s!'%data)
sock.close()
print 'Connection from %s:%s closed.'%addr
while True:
#接受一个新连接
sock,addr=s.accept()
#创建新线程来处理TCP连接
t=threading.Thread(target=tcp_link(sock,addr))

View File

@ -0,0 +1,266 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-01-24 ChungHsuan improve code comments
*/
#include <rtthread.h>
#include <string.h>
#include <stdlib.h>
#if !defined(SAL_USING_POSIX)
#error "Please enable SAL_USING_POSIX!"
#else
#include <sys/time.h>
#include <sys/select.h>
#endif
#include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket需要包含socket.h头文件 */
#include "netdb.h"
#define DEBUG_TCP_CLIENT
#define DBG_TAG "TCP"
#ifdef DEBUG_TCP_CLIENT
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO /* DBG_ERROR */
#endif
#include <rtdbg.h>
#define BUFSZ 1024
static int started = 0;
static int is_running = 0;
static char url[256];
static int port = 8080;
static const char send_data[] = "This is TCP Client from RT-Thread."; /* The message be sent */ /* 发送用到的数据 */
/**
* @brief This function is for creating a tcp client on RT-Thread
*/
static void tcpclient(void *arg)
{
int ret;
char *recv_data;
int bytes_received;
int sock = -1;
struct hostent *host = RT_NULL;
struct sockaddr_in server_addr;
struct timeval timeout;
fd_set readset;
/* Get host address by parameter url(Domain name resolution if input domain) */
/* 通过函数入口参数url获得host地址如果是域名会做域名解析 */
host = gethostbyname(url);
if (host == RT_NULL)
{
LOG_E("Get host by name failed!");
return;
}
/* Allocate space for recv_data */
/* 分配用于存放接收数据的缓冲 */
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
LOG_E("No memory");
return;
}
/* Create a socket and set it to SOCK_STREAM(TCP) */
/* 创建一个socket类型是SOCKET_STREAMTCP类型 */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* Failed on creating socket */
/* 创建socket失败 */
LOG_E("Create socket error");
goto __exit;
}
/* Initialize server side address */
/* 初始化预连接的服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* Connect to server */
/* 连接到服务端 */
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
/* Failed on connecting to server */
/* 连接失败 */
LOG_E("Connect fail!");
goto __exit;
}
started = 1;
is_running = 1;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
while (is_running)
{
FD_ZERO(&readset);
FD_SET(sock, &readset);
/* Wait for read */
if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
continue;
/* Receive the maximum size 1024 bytes from socket */
/* 从sock连接中接收最大BUFSZ - 1字节数据 */
bytes_received = recv(sock, recv_data, BUFSZ - 1, 0);
if (bytes_received < 0)
{
/* Receive failed and close the connection */
/* 接收失败,关闭这个连接 */
LOG_E("Received error(%d), close the socket.", errno);
goto __exit;
}
else if (bytes_received == 0)
{
/* Socket has performed an orderly shutdown. */
/* 连接已断开 */
LOG_E("Socket has performed an orderly shutdown.");
goto __exit;
}
else
{
/* Receive data successfully and append '\0' at the end of message */
/* 有接收到数据,把末端清零 */
recv_data[bytes_received] = '\0';
if (rt_strcmp(recv_data, "q") == 0 || rt_strcmp(recv_data, "Q") == 0)
{
/* If the first letter is 'q' or 'Q', close the connection */
/* 如果是首字母是q或Q关闭这个连接 */
LOG_I("Got a 'q' or 'Q', close the socket.");
goto __exit;
}
else
{
/* Show the message in terminal */
/* 在控制终端显示收到的数据 */
LOG_D("Received data = %s", recv_data);
}
}
/* Send message to connected socket */
/* 发送数据到sock连接 */
ret = send(sock, send_data, rt_strlen(send_data), 0);
if (ret < 0)
{
/* Send failed, close the connection */
/* 发送失败,关闭这个连接 */
LOG_I("send error(%d), close the socket.", errno);
goto __exit;
}
else if (ret == 0)
{
/* Socket has performed an orderly shutdown. */
/* 连接已断开 */
LOG_E("Socket has performed an orderly shutdown.");
goto __exit;
}
else if (ret != rt_strlen(send_data))
{
LOG_W("%d out of %d bytes sent.", ret, rt_strlen(send_data));
}
}
__exit:
if (recv_data)
{
rt_free(recv_data);
recv_data = RT_NULL;
}
if (sock >= 0)
{
closesocket(sock);
sock = -1;
}
started = 0;
is_running = 0;
return;
}
/**
* @brief The usage description of tcp client on rt-Thread
*/
static void usage(void)
{
rt_kprintf("Usage: tcpclient -h <host> -p <port>\n");
rt_kprintf(" tcpclient --stop\n");
rt_kprintf(" tcpclient --help\n");
rt_kprintf("\n");
rt_kprintf("Miscellaneous:\n");
rt_kprintf(" -h Specify host address\n");
rt_kprintf(" -p Specify the host port number\n");
rt_kprintf(" --stop Stop tcpclient program\n");
rt_kprintf(" --help Print help information\n");
}
/**
* @brief This function is for testing tcp client on rt-Thread
*/
static void tcpclient_test(int argc, char** argv)
{
rt_thread_t tid;
if (argc == 1 || argc > 5)
{
LOG_I("Please check the command you entered!\n");
goto __usage;
}
else
{
if (rt_strcmp(argv[1], "--help") == 0)
{
goto __usage;
}
else if (rt_strcmp(argv[1], "--stop") == 0)
{
is_running = 0;
return;
}
else if (rt_strcmp(argv[1], "-h") == 0 && rt_strcmp(argv[3], "-p") == 0)
{
if (started)
{
LOG_I("The tcpclient has started!");
LOG_I("Please stop tcpclient firstly, by: tcpclient --stop");
return;
}
if (rt_strlen(argv[2]) > sizeof(url))
{
LOG_E("The input url is too long, max %d bytes!", sizeof(url));
return;
}
rt_memset(url, 0x0, sizeof(url));
rt_strncpy(url, argv[2], rt_strlen(argv[2]));
port = atoi(argv[4]);
}
else
{
goto __usage;
}
}
tid = rt_thread_create("tcp_client",
tcpclient, RT_NULL,
2048, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
return;
__usage:
usage();
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(tcpclient_test, tcpclient,
Start a tcp client. Help: tcpclient --help);
#endif

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rtthread.h>
#include <netdb.h> /* 为了解析主机名需要包含netdb.h头文件 */
#include <sys/socket.h> /* 使用BSD socket需要包含socket.h头文件 */
void tcp_senddata(const char *url, int port, int length)
{
struct hostent *host;
int sock, err, result, timeout, index;
struct sockaddr_in server_addr;
rt_uint8_t *buffer_ptr;
/* 通过函数入口参数url获得host地址如果是域名会做域名解析 */
host = gethostbyname(url);
/* 创建一个socket类型是SOCKET_STREAMTCP类型 */
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
/* 创建socket失败 */
rt_kprintf("Socket error\n");
return;
}
/* 申请内存 */
buffer_ptr = rt_malloc(length);
if(RT_NULL == buffer_ptr)
{
/* 申请内存失败 */
rt_kprintf("No memory\n");
return;
}
/* 构造发送数据 */
for (index = 0; index < length; index ++)
buffer_ptr[index] = index & 0xff;
timeout = 100;
/* 设置发送超时时间100ms */
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
/* 初始化预连接的服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* 连接到服务端 */
err = connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
rt_kprintf("TCP thread connect error code: %d\n", err);
while (1)
{
/* 发送数据到sock连接 */
result = send(sock, buffer_ptr, length, MSG_DONTWAIT);
if (result < 0) //数据发送错误处理
{
rt_kprintf("TCP thread send error: %d\n", result);
closesocket(sock);
/* 关闭连接,重新创建连接 */
rt_thread_delay(10);
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
rt_kprintf("TCP Socket error:%d\n", sock);
err = connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
rt_kprintf("TCP thread connect error code: %d\n", err);
}
else if (result == 0)
{
/* 打印send函数返回值为0的警告信息 */
rt_kprintf("\n Send warning,send function returns 0.\r\n");
}
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
/* 输出tcpclient函数到finsh shell中 */
FINSH_FUNCTION_EXPORT(tcp_senddata, send a packet through tcp connection);
#endif

View File

@ -0,0 +1,296 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-01-24 ChungHsuan improve code comments
*/
#include <rtthread.h>
#include <string.h>
#include <stdlib.h>
#if !defined(SAL_USING_POSIX)
#error "Please enable SAL_USING_POSIX!"
#else
#include <sys/time.h>
#include <sys/select.h>
#endif
#include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket需要包含socket.h头文件 */
#include "netdb.h"
#define DEBUG_TCP_SERVER
#define DBG_TAG "TCP"
#ifdef DEBUG_TCP_SERVER
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO /* DBG_ERROR */
#endif
#include <rtdbg.h>
#define BUFSZ (1024)
static int started = 0;
static int is_running = 0;
static int port = 5000;
static const char send_data[] = "This is TCP Server from RT-Thread."; /* The message be sent */ /* 发送用到的数据 */
/**
* @brief This function is for creating a tcp server on RT-Thread
*/
static void tcpserv(void *arg)
{
int ret;
char *recv_data; /* recv_data is a pointer used to receive data */ /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */
int sock, connected, bytes_received;
struct sockaddr_in server_addr, client_addr;
struct timeval timeout;
fd_set readset, readset_c;
socklen_t sin_size = sizeof(struct sockaddr_in);
recv_data = rt_malloc(BUFSZ + 1);/* Allocate space for recv_data */ /* 分配接收用的数据缓冲 */
if (recv_data == RT_NULL)
{
LOG_E("No memory");
return;
}
/* Before making use of socket, socket should be created first and set the socket created to SOCK_STREAM(TCP) */
/* 一个socket在使用前需要预先创建出来指定SOCK_STREAM为TCP的socket */
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
LOG_E("Create socket error");
goto __exit;
}
/* Initialize server side address */
/* 初始化服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port); /*Server side port number*//* 服务端工作的端口 */
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
/* Bind socket to server side address */
/* 绑定socket到服务端地址 */
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
LOG_E("Unable to bind");
goto __exit;
}
/* Listen on socket */
/* 在socket上进行监听 */
if (listen(sock, 10) == -1)
{
LOG_E("Listen error");
goto __exit;
}
LOG_I("\nTCPServer Waiting for client on port %d...\n", port);
started = 1;
is_running = 1;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
while (is_running)
{
FD_ZERO(&readset);
FD_SET(sock, &readset);
LOG_I("Waiting for a new connection...");
/* Wait for read or write */
if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
continue;
/* Accept a request from client and the function is blocking */
/* 接受一个客户端连接socket的请求这个函数调用是阻塞式的 */
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
/* Return the socket connected successfully */
/* 返回的是连接成功的socket */
if (connected < 0)
{
LOG_E("accept connection failed! errno = %d", errno);
continue;
}
/* Accept the message which points by client address */
/* 接受返回的client_addr指向了客户端的地址信息 */
LOG_I("I got a connection from (%s , %d)\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
/* Handle method of client connection */
/* 客户端连接的处理 */
while (is_running)
{
FD_ZERO(&readset_c);
FD_SET(connected, &readset_c);
/* Wait for read or write */
if (select(connected + 1, &readset_c, RT_NULL, RT_NULL, &timeout) == 0)
continue;
/* Receive message from connected socket. Buffer size is 1024 bytes,but it's not guranteed to receive size exactly 1024 */
/* 从connected socket中接收数据接收buffer是1024大小但并不一定能够收到1024大小的数据 */
bytes_received = recv(connected, recv_data, BUFSZ, 0);
if (bytes_received < 0)
{
LOG_E("Received error(%d), close the connect.", errno);
closesocket(connected);
connected = -1;
break;
}
else if (bytes_received == 0)
{
/* Socket has performed an orderly shutdown */
/* 连接已断开 */
LOG_E("Socket has performed an orderly shutdown.");
closesocket(connected);
connected = -1;
break;
}
else
{ /* Receive data successfully and append '\0' at the end of message */
/* 有接收到数据,把末端清零 */
recv_data[bytes_received] = '\0';
if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
{
/* If the first letter is 'q' or 'Q', close the connection */
/* 如果是首字母是q或Q关闭这个连接 */
LOG_I("Got a 'q' or 'Q', close the connect.");
closesocket(connected);
connected = -1;
break;
}
else if (strcmp(recv_data, "exit") == 0)
{
/* If the message received is 'exit', close the whole server side. */
/* 如果接收的是exit则关闭整个服务端 */
closesocket(connected);
connected = -1;
goto __exit;
}
else
{
/* Show the message in terminal */
/* 在控制终端显示收到的数据 */
LOG_D("Received data = %s", recv_data);
}
}
/* Send message to connected socket */
/* 发送数据到connected socket */
ret = send(connected, send_data, rt_strlen(send_data), 0);
if (ret < 0)
{
LOG_E("send error(%d), close the connect.", errno);
closesocket(connected);
connected = -1;
break;
}
else if (ret == 0)
{
/* Socket has performed an orderly shutdown */
/* 连接已断开 */
LOG_E("Socket has performed an orderly shutdown.");
closesocket(connected);
connected = -1;
break;
}
else if (ret != rt_strlen(send_data))
{
LOG_W("%d out of %d bytes sent.", ret, rt_strlen(send_data));
}
}
}
__exit:
if (recv_data)
{
rt_free(recv_data);
recv_data = RT_NULL;
}
if (connected >= 0)
{
closesocket(connected);
connected = -1;
}
if (sock >= 0)
{
closesocket(sock);
sock = -1;
}
started = 0;
is_running = 0;
return;
}
/**
* @brief The usage description of tcp server on rt-Thread
*/
static void usage(void)
{
rt_kprintf("Usage: tcpserver -p <port>\n");
rt_kprintf(" tcpserver --stop\n");
rt_kprintf(" tcpserver --help\n");
rt_kprintf("\n");
rt_kprintf("Miscellaneous:\n");
rt_kprintf(" -p Specify the host port number\n");
rt_kprintf(" --stop Stop tcpserver program\n");
rt_kprintf(" --help Print help information\n");
}
/**
* @brief This function is for testing tcp server on rt-Thread
*/
static void tcpserver_test(int argc, char** argv)
{
rt_thread_t tid;
if (argc == 1 || argc > 3)
{
LOG_I("Please check the command you entered!\n");
goto __usage;
}
else
{
if (rt_strcmp(argv[1], "--help") == 0)
{
goto __usage;
}
else if (rt_strcmp(argv[1], "--stop") == 0)
{
is_running = 0;
return;
}
else if (rt_strcmp(argv[1], "-p") == 0)
{
if (started)
{
LOG_I("The tcpserver has started!");
LOG_I("Please stop tcpserver firstly, by: tcpserver --stop");
return;
}
port = atoi(argv[2]);
}
else
{
goto __usage;
}
}
tid = rt_thread_create("tcp_serv",
tcpserv, RT_NULL,
2048, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
return;
__usage:
usage();
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(tcpserver_test, tcpserver,
Start a tcp server. Help: tcpserver --help);
#endif

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-01-24 ChungHsuan improve code comments
*/
#include <rtthread.h>
#include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket需要包含sockets.h头文件 */
#include "netdb.h"
#define DEBUG_UDP_CLIENT
#define DBG_TAG "UDP"
#ifdef DEBUG_UDP_CLIENT
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO /* DBG_ERROR */
#endif
#include <rtdbg.h>
static int started = 0;
static int is_running = 0;
static char url[256];
static int port = 8080;
static int count = 10;
const char send_data[] = "This is UDP Client from RT-Thread.\n";/* The message be sent */ /* 发送用到的数据 */
/**
* @brief This function is for creating a udp client on RT-Thread
*/
static void udpclient(void *arg)
{
int sock;
struct hostent *host;
struct sockaddr_in server_addr;
/* Get host address by parameter URL (domain name resolution if input domain) */
/* 通过函数入口参数url获得host地址如果是域名会做域名解析 */
host = (struct hostent *) gethostbyname(url);
if (host == RT_NULL)
{
LOG_E("Get host by name failed!");
return;
}
/* Create a socket and set it to SOCK_DGRAM(UDP) */
/* 创建一个socket类型是SOCK_DGRAMUDP类型 */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
/* Failed on creating socket */
LOG_E("Create socket error");
return;
}
/* Initialize server side address */
/* 初始化预连接的服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
started = 1;
is_running = 1;
/* The total sending number(count) */
/* 总计发送count次数据 */
while (count && is_running)
{
/* Send message to server side */
/* 发送数据到服务远端 */
sendto(sock, send_data, rt_strlen(send_data), 0,
(struct sockaddr *)&server_addr, sizeof(struct sockaddr));
/* Thread sleep for 1 second */
/* 线程休眠一段时间 */
rt_thread_mdelay(1000);
/* count decrease 1 */
/* 计数值减一 */
count --;
}
if (count == 0)
{
LOG_I("UDP client send data finished!");
}
/* Close the socket */
/* 关闭这个socket */
if (sock >= 0)
{
closesocket(sock);
sock = -1;
}
started = 0;
is_running = 0;
}
/**
* @brief The usage description of udp client on rt-Thread
*/
static void usage(void)
{
rt_kprintf("Usage: udpclient -h <host> -p <port> [--cnt] [count]\n");
rt_kprintf(" udpclient --stop\n");
rt_kprintf(" udpclient --help\n");
rt_kprintf("\n");
rt_kprintf("Miscellaneous:\n");
rt_kprintf(" -h Specify host address\n");
rt_kprintf(" -p Specify the host port number\n");
rt_kprintf(" --cnt Specify the send data count\n");
rt_kprintf(" --stop Stop udpclient program\n");
rt_kprintf(" --help Print help information\n");
}
/**
* @brief This function is for testing udp client on rt-Thread
*/
static void udpclient_test(int argc, char** argv)
{
rt_thread_t tid;
if (argc == 1 || argc > 7)
{
LOG_I("Please check the command you entered!\n");
goto __usage;
}
else
{
if (rt_strcmp(argv[1], "--help") == 0)
{
goto __usage;
}
else if (rt_strcmp(argv[1], "--stop") == 0)
{
is_running = 0;
return;
}
else if (rt_strcmp(argv[1], "-h") == 0 && rt_strcmp(argv[3], "-p") == 0)
{
if (started)
{
LOG_I("The udpclient has started!");
LOG_I("Please stop udpclient firstly, by: udpclient --stop");
return;
}
if (argc == 7 && rt_strcmp(argv[6], "--cnt") == 0)
{
count = atoi(argv[7]);
}
if (rt_strlen(argv[2]) > sizeof(url))
{
LOG_E("The input url is too long, max %d bytes!", sizeof(url));
return;
}
rt_memset(url, 0x0, sizeof(url));
rt_strncpy(url, argv[2], rt_strlen(argv[2]));
port = atoi(argv[4]);
}
else
{
goto __usage;
}
}
tid = rt_thread_create("udp_client",
udpclient, RT_NULL,
2048, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
return;
__usage:
usage();
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(udpclient_test, udpclient,
Start a udp client. Help: udpclient --help);
#endif

View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-01-24 ChungHsuan improve code comments
*/
#include <rtthread.h>
#include <string.h>
#if !defined(SAL_USING_POSIX)
#error "Please enable SAL_USING_POSIX!"
#else
#include <sys/time.h>
#include <sys/select.h>
#endif
#include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket需要包含socket.h头文件 */
#include "netdb.h"
#define DEBUG_UDP_SERVER
#define DBG_TAG "UDP"
#ifdef DEBUG_UDP_SERVER
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO /* DBG_ERROR */
#endif
#include <rtdbg.h>
#define BUFSZ 1024
static int started = 0;
static int is_running = 0;
static int port = 5000;
/**
* @brief This function is for creating a udp server on RT-Thread
*/
static void udpserv(void *paramemter)
{
int sock;
int bytes_read;
char *recv_data;
socklen_t addr_len;
struct sockaddr_in server_addr, client_addr;
struct timeval timeout;
fd_set readset;
/* Allocate space for recv_data */
/* 分配接收用的数据缓冲 */
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
LOG_E("No memory");
return;
}
/* Create a socket and set it to SOCK_DGRAM(UDP) */
/* 创建一个socket类型是SOCK_DGRAMUDP类型 */
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
LOG_E("Create socket error");
goto __exit;
}
/* Initialize server side address */
/* 初始化服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* Bind socket to server side address */
/* 绑定socket到服务端地址 */
if (bind(sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
LOG_E("Unable to bind");
goto __exit;
}
addr_len = sizeof(struct sockaddr);
LOG_I("UDPServer Waiting for client on port %d...", port);
started = 1;
is_running = 1;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
while (is_running)
{
FD_ZERO(&readset);
FD_SET(sock, &readset);
/* Wait for read or write */
if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
continue;
/* The maximum size received from sock is BUFSZ-1 bytes*/
/* 从sock中收取最大BUFSZ - 1字节数据 */
bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
(struct sockaddr *)&client_addr, &addr_len);
if (bytes_read < 0)
{
LOG_E("Received error, close the connect.");
goto __exit;
}
else if (bytes_read == 0)
{
LOG_W("Received warning, recv function returns 0.");
continue;
}
else
{
recv_data[bytes_read] = '\0'; /* Append '\0' at the end of message *//* 把末端清零 */
/* Output received message */
/* 输出接收的数据 */
LOG_D("Received data = %s", recv_data);
/* If the message received is 'exit', quit. */
/* 如果接收数据是exit退出 */
if (strcmp(recv_data, "exit") == 0)
{
goto __exit;
}
}
}
__exit:
if (recv_data)
{
rt_free(recv_data);
recv_data = RT_NULL;
}
if (sock >= 0)
{
closesocket(sock);
sock = -1;
}
started = 0;
is_running = 0;
}
/**
* @brief The usage description of udp server on rt-Thread
*/
static void usage(void)
{
rt_kprintf("Usage: udpserver -p <port>\n");
rt_kprintf(" udpserver --stop\n");
rt_kprintf(" udpserver --help\n");
rt_kprintf("\n");
rt_kprintf("Miscellaneous:\n");
rt_kprintf(" -p Specify the host port number\n");
rt_kprintf(" --stop Stop udpserver program\n");
rt_kprintf(" --help Print help information\n");
}
/**
* @brief This function is for testing udp server on rt-Thread
*/
static void udpserver_test(int argc, char** argv)
{
rt_thread_t tid;
if (argc == 1 || argc > 3)
{
LOG_I("Please check the command you entered!\n");
goto __usage;
}
else
{
if (rt_strcmp(argv[1], "--help") == 0)
{
goto __usage;
}
else if (rt_strcmp(argv[1], "--stop") == 0)
{
is_running = 0;
return;
}
else if (rt_strcmp(argv[1], "-p") == 0)
{
if (started)
{
LOG_I("The udpserver has started!");
LOG_I("Please stop udpserver firstly, by: udpserver --stop");
return;
}
port = atoi(argv[2]);
}
else
{
goto __usage;
}
}
tid = rt_thread_create("udp_serv",
udpserv, RT_NULL,
2048, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
return;
__usage:
usage();
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(udpserver_test, udpserver,
Start a udp server. Help: udpserver --help);
#endif

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-07 Tanek first implementation
* 2019-05-06 Zero-Free adapt to the new power management interface
*/
#include <board.h>
#include <rtthread.h>
#include <rtdevice.h>
#ifndef RT_USING_TIMER_SOFT
#error "Please enable soft timer feature!"
#endif
#define TIMER_APP_DEFAULT_TICK (RT_TICK_PER_SECOND * 2)
#ifdef RT_USING_PM
static rt_timer_t timer1;
static void _timeout_entry(void *parameter)
{
rt_kprintf("current tick: %ld\n", rt_tick_get());
}
static int timer_app_init(void)
{
timer1 = rt_timer_create("timer_app",
_timeout_entry,
RT_NULL,
TIMER_APP_DEFAULT_TICK,
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
if (timer1 != RT_NULL)
{
rt_timer_start(timer1);
/* keep in timer mode */
rt_pm_request(PM_SLEEP_MODE_DEEP);
return 0;
}
else
{
return -1;
}
}
INIT_APP_EXPORT(timer_app_init);
#endif /* RT_USING_PM */

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-09 Zero-Free first implementation
*/
#include <board.h>
#include <rtthread.h>
#include <rtdevice.h>
#ifdef RT_USING_PM
#define WAKEUP_EVENT_BUTTON (1 << 0)
#define PIN_LED_R GET_PIN(E, 7)
#define WAKEUP_PIN GET_PIN(C, 13)
#define WAKEUP_APP_THREAD_STACK_SIZE 1024
static rt_event_t wakeup_event;
static void wakeup_callback(void *args)
{
rt_event_send(wakeup_event, WAKEUP_EVENT_BUTTON);
}
static void wakeup_init(void)
{
rt_pin_mode(WAKEUP_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(WAKEUP_PIN, PIN_IRQ_MODE_FALLING, wakeup_callback, RT_NULL);
rt_pin_irq_enable(WAKEUP_PIN, 1);
}
static void wakeup_app_entry(void *parameter)
{
wakeup_init();
rt_pm_request(PM_SLEEP_MODE_DEEP);
while (1)
{
if (rt_event_recv(wakeup_event,
WAKEUP_EVENT_BUTTON,
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, RT_NULL) == RT_EOK)
{
rt_pm_request(PM_SLEEP_MODE_NONE);
rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
rt_pin_write(PIN_LED_R, 0);
rt_thread_delay(rt_tick_from_millisecond(500));
rt_pin_write(PIN_LED_R, 1);
rt_pm_release(PM_SLEEP_MODE_NONE);
}
}
}
static int wakeup_app(void)
{
rt_thread_t tid;
wakeup_event = rt_event_create("wakup", RT_IPC_FLAG_PRIO);
RT_ASSERT(wakeup_event != RT_NULL);
tid = rt_thread_create("wakeup_app", wakeup_app_entry, RT_NULL,
WAKEUP_APP_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(tid != RT_NULL);
rt_thread_startup(tid);
return 0;
}
INIT_APP_EXPORT(wakeup_app);
#endif

View File

@ -0,0 +1,400 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-19 Sherman the first version
*/
#include <string.h>
#include <stdlib.h>
#define DBG_TAG "example"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <rtlink_dev.h>
enum
{
NONE_TEST = 0,
SHORT_FRAME_TEST,
LONG_FRAME_TEST
};
static rt_uint8_t speed_test_type = NONE_TEST;
static struct rt_link_device rtlink_dev = {0};
#define RTLINK01 "rtlink01"
#define TEST_CONTEXT "This message is sent by RT-Link"
rt_uint8_t test_buff[1024] = {0};
static rt_err_t rtlink_dev_rx_ind(rt_device_t dev, rt_size_t size)
{
RT_ASSERT(dev != RT_NULL);
LOG_I("rx_ind: dev name %s, rx size %d", dev->parent.name, size);
return RT_EOK;
}
static rt_err_t rtlink_dev_tx_done(rt_device_t dev, void *buffer)
{
RT_ASSERT(dev != RT_NULL);
struct rt_link_device *rtlink_dev = (struct rt_link_device *)dev;
LOG_I("tx_done: dev name %s, buffer 0x%p errno %d", dev->parent.name, buffer, rtlink_dev->service.err);
rt_free(buffer);
return RT_EOK;
}
#ifdef RT_USING_POSIX_DEVIO
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <poll.h>
#include <sys/select.h>
#define RTLINK01_PATH "/dev/rtlink01"
int fd = -1;
static void rtlink_fopen(int argc, char *argv[])
{
fd = open(RTLINK01_PATH, O_RDWR | O_NONBLOCK);
if (fd < 0)
{
LOG_E("open rt_link failed!");
}
}
MSH_CMD_EXPORT(rtlink_fopen, rtlink posix interface example);
static void rtlink_fclose(int argc, char *argv[])
{
LOG_D("colse %d", fd);
close(fd);
fd = -1;
}
MSH_CMD_EXPORT(rtlink_fclose, rtlink posix interface example);
static void rtlink_fread(int argc, char *argv[])
{
int read_len;
read_len = read(fd, test_buff, sizeof(test_buff));
LOG_D("read len %d", read_len);
LOG_HEX("read", 8, test_buff, 32);
}
MSH_CMD_EXPORT(rtlink_fread, rtlink posix interface example);
static void rtlink_fwrite(int argc, char *argv[])
{
char *data = RT_NULL;
rt_size_t length = 0;
rt_uint16_t count = 0;
rt_size_t ret = 0;
if (argc == 1)
{
data = rt_malloc(sizeof(TEST_CONTEXT));
if (data)
{
length = sizeof(TEST_CONTEXT) - 1;
rt_memcpy(data, TEST_CONTEXT, sizeof(TEST_CONTEXT) - 1);
ret = write(fd, data, length);
}
LOG_I("write data(0x%p) result: %d.", data, ret);
}
else if (argc >= 3)
{
if (strcmp(argv[1], "-l") == 0)
{
data = rt_malloc(atoi((const char *)argv[2]));
if (data)
{
for (count = 0; count < atoi((const char *)argv[2]); count++)
{
data[count] = (count % 93 + 33);
}
length = atoi((const char *)argv[2]);
ret = write(fd, data, length);
}
LOG_I("write data(0x%p) result: %d.", data, ret);
}
else
{
LOG_E("Invalid parameter.");
}
}
}
MSH_CMD_EXPORT(rtlink_fwrite, rtlink posix interface example);
#define RTLINK02 "rtlink02"
#define RTLINK02_PATH "/dev/rtlink02"
static struct rt_link_device rtlink_fd = {0};
rt_uint8_t fd_buff[1024] = {0};
static void listen_thread(void *param)
{
int fd = open(RTLINK02_PATH, O_RDWR | O_NONBLOCK);
if (fd < 0)
{
LOG_E("open (%s) failed", RTLINK02);
return;
}
while (1)
{
rt_uint8_t *write_buf = RT_NULL;
int write_len = 0;
fd_set readfds, writefds;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(fd, &readfds);
FD_SET(fd, &writefds);
int ret = select(fd + 1, &readfds, &writefds, RT_NULL, RT_NULL);
LOG_D("select ret(%d), read (%d), write (%d)", ret, readfds, writefds);
if (FD_ISSET(fd, &readfds))
{
LOG_I("POLLIN");
int read_len = read(fd, fd_buff, sizeof(test_buff));
LOG_D("read len %d", read_len);
LOG_HEX("read", 8, test_buff, 32);
}
if (FD_ISSET(fd, &writefds))
{
LOG_I("POLLOUT");
write_buf = rt_malloc(1024);
if (write_buf)
{
write_len = write(fd, write_buf, 1024);
LOG_D("write %d", write_len);
}
}
rt_thread_delay(500);
}
LOG_I("fd (%s) listen thread exit", RTLINK02);
}
static void rtlink_fselect()
{
/* step1: register rtlink to to the device framework */
rt_link_dev_register(&rtlink_fd, RTLINK02,
RT_DEVICE_FLAG_RDWR |
RT_DEVICE_FLAG_REMOVABLE |
RT_DEVICE_FLAG_STANDALONE,
RT_NULL);
/* step2: Initialize the rlink device as the default configuration, */
rt_device_t device = rt_device_find(RTLINK02);
if (device == RT_NULL)
{
LOG_E("device not find!");
return ;
}
rt_device_init(device);
/* step3: config rtlink device rx/tx callback, channel, send timeout */
rt_device_set_rx_indicate(device, rtlink_dev_rx_ind);
rt_device_set_tx_complete(device, rtlink_dev_tx_done);
struct rt_link_service service;
service.service = RT_LINK_SERVICE_MNGT;
service.timeout_tx = RT_WAITING_NO;
rt_device_control(device, RT_DEVICE_CTRL_CONFIG, &service);
rt_thread_t tid = rt_thread_create(RTLINK02, listen_thread, RT_NULL, 1024, 21, 20);
if (tid)
{
rt_thread_startup(tid);
}
}
MSH_CMD_EXPORT(rtlink_fselect, rtlink posix interface example);
#endif /* RT_USING_POSIX_DEVIO */
static void rtlink_dread(void)
{
rt_size_t read_len = 0;
rt_device_t dev = rt_device_find(RTLINK01);
if (dev == RT_NULL)
{
LOG_E("dev %s not find ", RTLINK01);
return;
}
read_len = rt_device_read(dev, 0, test_buff, sizeof(test_buff));
LOG_D("read len %d", read_len);
LOG_HEX("read", 8, test_buff, 32);
}
MSH_CMD_EXPORT(rtlink_dread, rtlink device interface example);
void rt_link_speed_test(void *paremeter)
{
int ret;
rt_uint8_t *send_buf, *data;
rt_size_t bufflen = 0;
rt_size_t sentlen = 0;
rt_size_t count = 0;
rt_tick_t tick1, tick2;
rt_size_t total = 0;
rt_uint32_t integer, decimal;
rt_device_t dev = rt_device_find(RTLINK01);
if (dev == RT_NULL)
{
LOG_E("dev %s not find!", RTLINK01);
return ;
}
if (speed_test_type == SHORT_FRAME_TEST)
{
bufflen = 988;
}
else
{
bufflen = 3036;
}
send_buf = rt_malloc(bufflen);
if (send_buf != RT_NULL)
{
data = send_buf;
for (count = 0; count < bufflen; count++)
{
*data++ = (count % 93 + 33);
}
}
else
{
rt_kprintf("speed of send buffer malloc failed.");
return;
}
tick1 = rt_tick_get();
while (speed_test_type)
{
ret = rt_device_write(dev, 0, send_buf, bufflen);
if (ret == RT_EOK)
{
sentlen += bufflen;
}
tick2 = rt_tick_get();
if (tick2 - tick1 >= RT_TICK_PER_SECOND)
{
total = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
integer = total / 1000;
decimal = total % 1000;
LOG_I("%d.%03d0 Mbps!", integer, decimal);
sentlen = 0;
tick1 = tick2;
}
}
rt_free(send_buf);
LOG_W("speed test end, type %d", speed_test_type);
}
void create_thead_to_test_speed(rt_uint8_t mutil_num)
{
rt_uint8_t i = 0;
LOG_D("Speed test type [%02d], mutil [%02d]", speed_test_type, mutil_num);
for (i = 0; i < mutil_num; i++)
{
rt_thread_t tid;
char tid_name[RT_NAME_MAX + 1] = {0};
rt_snprintf(tid_name, sizeof(tid_name), "lny_s%03d", i + 1);
tid = rt_thread_create(tid_name, rt_link_speed_test, RT_NULL, 1024, 20, 10);
rt_thread_startup(tid);
LOG_I("Speed test thread[%s] startup", tid_name);
}
}
static rt_err_t rtlink_dwrite(int argc, char *argv[])
{
char *data = RT_NULL;
rt_size_t length = 0;
rt_uint16_t count = 0;
rt_size_t ret = -RT_ERROR;
rt_device_t dev = rt_device_find(RTLINK01);
if (dev == RT_NULL)
{
LOG_E("device not find!");
return ret;
}
if (argc == 1)
{
data = rt_malloc(sizeof(TEST_CONTEXT));
length = sizeof(TEST_CONTEXT) - 1;
rt_memcpy(data, TEST_CONTEXT, sizeof(TEST_CONTEXT) - 1);
ret = rt_device_write(dev, 0, data, length);
LOG_I("write data(0x%p) result: %d.", data, ret);
}
else if (argc >= 3)
{
if (strcmp(argv[1], "-l") == 0)
{
data = rt_malloc(atoi((const char *)argv[2]));
for (count = 0; count < atoi((const char *)argv[2]); count++)
{
data[count] = (count % 93 + 33);
}
length = atoi((const char *)argv[2]);
ret = rt_device_write(dev, 0, data, length);
LOG_I("write data(0x%p) result: %d.", data, ret);
}
else
{
LOG_E("Invalid parameter.");
}
}
return ret;
}
MSH_CMD_EXPORT(rtlink_dwrite, rtlink device interface example);
static void rtlink_dinit(void)
{
/* step1: register rtlink to to the device framework */
rt_link_dev_register(&rtlink_dev, RTLINK01,
RT_DEVICE_FLAG_RDWR |
RT_DEVICE_FLAG_REMOVABLE |
RT_DEVICE_FLAG_STANDALONE,
RT_NULL);
/* step2: Initialize the rlink device as the default configuration, */
rt_device_t device = rt_device_find(RTLINK01);
if (device == RT_NULL)
{
LOG_E("device not find!");
return ;
}
rt_device_init(device);
/* step3: config rtlink device rx/tx callback, channel, send timeout */
rt_device_set_rx_indicate(device, rtlink_dev_rx_ind);
rt_device_set_tx_complete(device, rtlink_dev_tx_done);
struct rt_link_service service;
service.service = RT_LINK_SERVICE_SOCKET;
service.timeout_tx = RT_WAITING_FOREVER;
service.flag = RT_LINK_FLAG_ACK | RT_LINK_FLAG_CRC;
rt_device_control(device, RT_DEVICE_CTRL_CONFIG, &service);
}
MSH_CMD_EXPORT(rtlink_dinit, rtlink device interface example);
static void rtlink_dopen()
{
/* step4: open rtlink device, attach the service channel */
rt_device_t device = rt_device_find(RTLINK01);
if (device == RT_NULL)
{
LOG_E("device not find!");
return ;
}
rt_err_t ret = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
LOG_I("dev open ret %d", ret);
}
MSH_CMD_EXPORT(rtlink_dopen, rtlink device interface example);

View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-15 Sherman the first version
* 2021-08-04 Sherman Adapted to new version of rt-link API
*/
#include <stdlib.h>
#include <string.h>
#include <rtthread.h>
#include <rtlink.h>
#define DBG_ENABLE
#define DBG_TAG "rtlink_exam"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define TEST_CONTEXT "This message is sent by RT-Link"
enum
{
NONE_TEST = 0,
SHORT_FRAME_TEST,
LONG_FRAME_TEST
};
void rt_link_speed_test(void *paremeter);
static rt_uint8_t speed_test_type = NONE_TEST;
static struct rt_link_service serv_socket;
static struct rt_link_service serv_wifi;
static void send_cb(struct rt_link_service *service, void *buffer)
{
LOG_I("send_cb: service (%d) buffer (0x%p) err(%d)", service->service, buffer, service->err);
}
static void recv_cb(struct rt_link_service *service, void *data, rt_size_t size)
{
LOG_I("service (%d) size (%d) data(0x%p)", service->service, size, data);
if (size)
{
rt_free(data);
}
}
static void rt_link_speed_test(void *paremeter)
{
int ret;
rt_uint8_t *send_buf, *data;
rt_size_t bufflen = 0;
rt_size_t sentlen = 0;
rt_size_t count = 0;
rt_tick_t tick1, tick2;
rt_size_t total = 0;
rt_uint32_t integer, decimal;
if (speed_test_type == SHORT_FRAME_TEST)
{
bufflen = RT_LINK_MAX_DATA_LENGTH;
}
else
{
bufflen = RT_LINK_MAX_DATA_LENGTH * RT_LINK_FRAMES_MAX;
}
send_buf = rt_malloc(bufflen);
if (send_buf != RT_NULL)
{
data = send_buf;
for (count = 0; count < bufflen; count++)
{
*data++ = (count % 93 + 33);
}
}
else
{
rt_kprintf("speed of send buffer malloc failed.");
return;
}
tick1 = rt_tick_get();
while (speed_test_type)
{
ret = rt_link_send(&serv_socket, send_buf, bufflen);
if (ret > 0)
{
sentlen += ret;
}
else
{
LOG_W("send err %d", ret);
}
tick2 = rt_tick_get();
if (tick2 - tick1 >= RT_TICK_PER_SECOND)
{
total = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
integer = total / 1000;
decimal = total % 1000;
LOG_I("%d.%03d0 Mbps!", integer, decimal);
sentlen = 0;
tick1 = tick2;
}
}
rt_free(send_buf);
LOG_W("speed test end, type %d", speed_test_type);
}
static void create_thead_to_test_speed(rt_uint8_t mutil_num)
{
rt_uint8_t i = 0;
LOG_D("Speed test type [%02d], mutil [%02d]", speed_test_type, mutil_num);
for (i = 0; i < mutil_num; i++)
{
rt_thread_t tid;
char tid_name[RT_NAME_MAX + 1] = {0};
rt_snprintf(tid_name, sizeof(tid_name), "lny_s%03d", i + 1);
tid = rt_thread_create(tid_name, rt_link_speed_test, RT_NULL, 1024, 20, 10);
if (tid)
{
rt_thread_startup(tid);
LOG_I("Speed test thread[%s] startup", tid_name);
}
}
}
static int rtlink_exsend(int argc, char **argv)
{
char *receive = RT_NULL;
rt_size_t length = 0;
rt_uint16_t count = 0;
if (argc == 1)
{
receive = rt_malloc(sizeof(TEST_CONTEXT));
rt_memcpy(receive, TEST_CONTEXT, sizeof(TEST_CONTEXT) - 1);
length = rt_link_send(&serv_socket, receive, sizeof(TEST_CONTEXT) - 1);
LOG_I("send data length: %d.", length);
rt_free(receive);
}
else if (argc >= 3)
{
if (strcmp(argv[1], "-l") == 0)
{
receive = rt_malloc(atoi((const char *)argv[2]));
for (count = 0; count < atoi((const char *)argv[2]); count++)
{
*receive++ = (count % 93 + 33);
}
length = rt_link_send(&serv_socket, receive - atoi((const char *)argv[2]), atoi((const char *)argv[2]));
rt_free(receive - atoi((const char *)argv[2]));
LOG_I("send data length: %d.", length);
}
else if (strcmp(argv[1], "-s") == 0)
{
if (speed_test_type == NONE_TEST)
{
rt_uint8_t mutil_num = 1;
if (argc > 3)
{
mutil_num = atoi((const char *)argv[3]);
}
if (strncmp(argv[2], "-s", rt_strlen(argv[2])) == 0)
{
speed_test_type = SHORT_FRAME_TEST;
}
else if (strncmp(argv[2], "-l", rt_strlen(argv[2])) == 0)
{
speed_test_type = LONG_FRAME_TEST;
}
create_thead_to_test_speed(mutil_num);
}
else
{
speed_test_type = NONE_TEST;
LOG_I("set NONE_TEST");
}
}
else
{
LOG_E("Invalid parameter.");
}
}
return 0;
}
MSH_CMD_EXPORT(rtlink_exsend, rt link layer send test);
int rtlink_exinit(void)
{
serv_socket.service = RT_LINK_SERVICE_SOCKET;
serv_socket.timeout_tx = RT_WAITING_FOREVER;
serv_socket.flag = RT_LINK_FLAG_ACK | RT_LINK_FLAG_CRC;
serv_socket.recv_cb = recv_cb;
serv_socket.send_cb = send_cb;
rt_link_service_attach(&serv_socket);
serv_wifi.service = RT_LINK_SERVICE_WIFI;
serv_wifi.timeout_tx = RT_WAITING_FOREVER;
serv_wifi.flag = RT_NULL;
serv_wifi.recv_cb = recv_cb;
serv_wifi.send_cb = send_cb;
rt_link_service_attach(&serv_wifi);
return RT_EOK;
}
MSH_CMD_EXPORT(rtlink_exinit, rt link example init);

View File

@ -0,0 +1,585 @@
/**
* Here is the assertions to ensure rightness of bst maintenance
* After each insertion and delete, a tree must still be binary search tree,
* and still remain balanced
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <mm_aspace.h>
#include <mm_private.h>
#define BUF_SIZE 1000000
static void *_start;
static void *_boundary;
static int _count;
static rt_varea_t _buf[BUF_SIZE];
#define RT_ASSERT assert
static void _print_varea(rt_varea_t varea, int depth)
{
if (depth == 0)
{
printf("%p ", varea->start);
}
else
{
rt_varea_t lchild = VAREA_ENTRY(varea->node.node.avl_left);
rt_varea_t rchild = VAREA_ENTRY(varea->node.node.avl_right);
depth--;
if (lchild)
_print_varea(lchild, depth);
else
printf("0x**** ");
if (rchild)
_print_varea(rchild, depth);
else
printf("0x**** ");
}
}
static void _print_tree(rt_aspace_t aspace)
{
rt_varea_t varea = VAREA_ENTRY(aspace->tree.tree.root_node);
if (!varea)
return ;
for (size_t i = 0; i < aspace->tree.tree.root_node->height; i++) {
_print_varea(varea, i);
putchar('\n');
}
return ;
}
static int _is_bst(rt_varea_t varea)
{
rt_varea_t lchild = VAREA_ENTRY(varea->node.node.avl_left);
rt_varea_t rchild = VAREA_ENTRY(varea->node.node.avl_right);
if (lchild)
{
RT_ASSERT(lchild->node.node.parent == &varea->node.node);
RT_ASSERT(varea->start > lchild->start);
}
if (rchild)
{
RT_ASSERT(rchild->node.node.parent == &varea->node.node);
if (varea->start >= rchild->start)
{
RT_ASSERT(0);
}
}
return 1;
}
/* return height of current varea */
static int _is_balanced(rt_varea_t varea)
{
if (!varea)
{
return 1;
}
rt_varea_t lchild = VAREA_ENTRY(varea->node.node.avl_left);
rt_varea_t rchild = VAREA_ENTRY(varea->node.node.avl_right);
int lbal = _is_balanced(lchild);
int rbal = _is_balanced(rchild);
if (lbal && rbal)
{
int diff = lbal - rbal;
if (diff > 1 || diff < -1)
{
printf("lbal %d, rbal %d\n", lbal, rbal);
return 0;
}
else
{
int height = lbal > rbal ? lbal : rbal;
return height + 1;
}
}
}
/* add bst assertion */
static int _check_asc_before(rt_varea_t varea, void *arg)
{
if (varea->start >= _start && (!_boundary || varea->start >= _boundary) && _is_bst(varea))
{
_buf[_count] = varea;
_start = varea->start;
_boundary = varea->start + varea->size;
_count++;
RT_ASSERT(_count < BUF_SIZE);
}
else
{
RT_ASSERT(0);
}
return 0;
}
static int _check_asc_before_rev(rt_varea_t varea, void *arg)
{
_count--;
RT_ASSERT(varea == _buf[_count]);
return 0;
}
static int _check_asc_after(rt_varea_t varea, void *arg)
{
rt_varea_t add_elem = (rt_varea_t)arg;
if (!_is_bst(varea))
{
RT_ASSERT(0);
}
if (varea == _buf[_count])
{
_buf[_count] = 0;
_count++;
RT_ASSERT(_count < BUF_SIZE);
}
else if (add_elem && add_elem == varea)
{
/* adding, skip adding elem */
}
else if (!add_elem && varea == _buf[_count + 1])
{
/* deleting */
_buf[_count] = 0;
_buf[_count] = 0;
_count++;
RT_ASSERT(_count < BUF_SIZE);
}
else
{
printf("add_elem %p, varea %p, _count %d, in buf %p\n",
add_elem->start, varea->start, _count, _buf[_count]);
RT_ASSERT(0);
}
return 0;
}
static int _aspace_traversal(rt_aspace_t aspace, int (*fn)(rt_varea_t varea, void *arg), void *arg)
{
rt_varea_t varea = ASPACE_VAREA_FIRST(aspace);
while (varea)
{
fn(varea, arg);
varea = ASPACE_VAREA_NEXT(varea);
}
return 0;
}
static int _aspace_traversal_reverse(rt_aspace_t aspace, int (*fn)(rt_varea_t varea, void *arg), void *arg)
{
rt_varea_t varea = ASPACE_VAREA_LAST(aspace);
while (varea)
{
fn(varea, arg);
varea = ASPACE_VAREA_PREV(varea);
}
return 0;
}
static int _check_bst_before(struct rt_aspace *aspace, struct rt_varea *varea)
{
rt_varea_t root = VAREA_ENTRY(aspace->tree.tree.root_node);
int height = _is_balanced(root);
if (root)
RT_ASSERT(height);
memset(_buf, 0, sizeof(_buf)); // clear first avoiding none tree error
_start = 0;
_boundary = 0;
_count = 0;
_aspace_traversal(aspace, _check_asc_before, varea);
int saved = _count;
_aspace_traversal_reverse(aspace, _check_asc_before_rev, varea);
_count = saved;
return 1;
}
static int _check_bst_after(struct rt_aspace *aspace, struct rt_varea *varea, int isdel)
{
rt_varea_t root = VAREA_ENTRY(aspace->tree.tree.root_node);
int height = _is_balanced(root);
if (root)
RT_ASSERT(height);
int prev_count = _count;
_start = 0;
_boundary = 0;
_count = 0;
_aspace_traversal(aspace, _check_asc_after, isdel ? NULL : varea);
_count = isdel ? _count : _count + 1;
if (isdel)
{
RT_ASSERT(prev_count - 1 == _count);
}
else
{
RT_ASSERT(prev_count + 1 == _count);
}
return 1;
}
/* test library */
#define RANDOM(n) (xrand() % (n))
static unsigned int xseed = 0x11223344;
static inline unsigned int xrand(void)
{
return (((xseed = xseed * 214013L + 2531011L) >> 16) & 0x7fffffff);
}
// generate keys
static inline void init_random_keys(int *keys, int count, int seed)
{
int save_seed = time(NULL);
int *array = (int*)malloc(sizeof(int) * count);
int length = count, i;
xseed = seed;
for (i = 0; i < count; i++) {
array[i] = i;
}
for (i = 0; i < length; i++) {
int pos = xrand() % count;
int key = array[pos];
keys[i] = key;
array[pos] = array[--count];
}
free(array);
xseed = save_seed;
}
// A utility function to swap to integers
static inline void swap (int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// A function to generate a random permutation of arr[]
static void randomize ( int arr[], int n )
{
// Use a different seed value so that we don't get same
// result each time we run this program
srand ( time(NULL) );
// Start from the last element and swap one by one. We don't
// need to run for the first element that's why i > 0
for (int i = n-1; i > 0; i--)
{
// Pick a random index from 0 to i
int j = rand() % (i+1);
// Swap arr[i] with the element at random index
swap(&arr[i], &arr[j]);
}
}
/* time */
#include <time.h>
static int gettime(void)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME_COARSE, &ts);
time_t seconds = ts.tv_sec;
int millisecond = ts.tv_nsec / 1000000;
return millisecond + seconds * 1000;
}
/* Adapt Layer */
/**
* @brief Adapter Layer for lwp AVL BST
*/
int _aspace_bst_init(struct rt_aspace *aspace)
{
aspace->tree.tree.root_node = AVL_ROOT;
return 0;
}
static int compare_overlap(void *as, void *ae, void *bs, void *be)
{
LOG_D("as %lx, ae %lx, bs %lx, be %lx", as, ae, bs, be);
int cmp;
if (as > be)
{
cmp = 1;
}
else if (ae < bs)
{
cmp = -1;
}
else
{
cmp = 0;
}
LOG_D("ret %d", cmp);
return cmp;
}
static int compare_exceed(void *as, void *ae, void *bs, void *be)
{
LOG_D("as %lx, ae %lx, bs %lx, be %lx", as, ae, bs, be);
int cmp;
if (as > bs)
{
cmp = 1;
}
else if (as < bs)
{
cmp = -1;
}
else
{
cmp = 0;
}
LOG_D("ret %d", cmp);
return cmp;
}
static struct rt_varea *search(struct util_avl_root *root,
struct _mm_range range,
int (*compare)(void *as, void *ae, void *bs,
void *be))
{
struct util_avl_struct *node = root->root_node;
while (node)
{
rt_varea_t varea = VAREA_ENTRY(node);
int cmp = compare(range.start, range.end, varea->start,
varea->start + varea->size - 1);
if (cmp < 0)
{
node = node->avl_left;
}
else if (cmp > 0)
{
node = node->avl_right;
}
else
{
return varea;
}
}
return NULL;
}
struct rt_varea *_aspace_bst_search(struct rt_aspace *aspace, void *key)
{
struct util_avl_root *root = &aspace->tree.tree;
struct _mm_range range = {key, key};
return search(root, range, compare_overlap);
}
rt_varea_t _aspace_bst_search_exceed(struct rt_aspace *aspace, void *start)
{
struct util_avl_root *root = &aspace->tree.tree;
struct util_avl_struct *node = root->root_node;
rt_varea_t closest = NULL;
ptrdiff_t min_off = PTRDIFF_MAX;
while (node)
{
rt_varea_t varea = VAREA_ENTRY(node);
void *va_s = varea->start;
int cmp = compare_exceed(start, start, va_s, va_s);
if (cmp < 0)
{
ptrdiff_t off = va_s - start;
if (off < min_off)
{
min_off = off;
closest = varea;
}
node = node->avl_left;
}
else if (cmp > 0)
{
node = node->avl_right;
}
else
{
return varea;
}
}
return closest;
}
struct rt_varea *_aspace_bst_search_overlap(struct rt_aspace *aspace,
struct _mm_range range)
{
struct util_avl_root *root = &aspace->tree.tree;
return search(root, range, compare_overlap);
}
#ifdef ENABLE_DEBUG
#include "bst_assert.h"
#else
#define _check_bst_before(x, ...)
#define _check_bst_after(x, ...)
#endif
void _aspace_bst_insert(struct rt_aspace *aspace, struct rt_varea *varea)
{
struct util_avl_root *root = &aspace->tree.tree;
struct util_avl_struct *current = NULL;
struct util_avl_struct **next = &(root->root_node);
rt_ubase_t key = (rt_ubase_t)varea->start;
/* Figure out where to put new node */
while (*next)
{
current = *next;
struct rt_varea *data = VAREA_ENTRY(current);
if (key < (rt_ubase_t)data->start)
next = &(current->avl_left);
else if (key > (rt_ubase_t)data->start)
next = &(current->avl_right);
else
return;
}
/* Add new node and rebalance tree. */
_check_bst_before(aspace, varea);
util_avl_link(&varea->node.node, current, next);
util_avl_rebalance(current, root);
_check_bst_after(aspace, varea, 0);
return;
}
void _aspace_bst_remove(struct rt_aspace *aspace, struct rt_varea *varea)
{
struct util_avl_struct *node = &varea->node.node;
_check_bst_before(aspace, varea);
util_avl_remove(node, &aspace->tree.tree);
_check_bst_after(aspace, varea, 1);
}
struct rt_aspace aspace;
/**
* @brief Simulate environment of varea and BSTs
*/
/* test data set */
int *dataset;
int loop_count;
/* preallocate varea to decrease influence by malloc routine */
struct rt_varea *_varea_buf;
#define STOPWATCH(fun, time) do { \
unsigned int _time; \
_time = gettime(); \
fun(); \
_time = gettime()-_time; \
time = _time; \
} while (0);
static void init_test(void)
{
_aspace_bst_init(&aspace);
dataset = malloc(loop_count * sizeof(*dataset));
assert(dataset);
_varea_buf = malloc(loop_count * sizeof(*_varea_buf));
assert(_varea_buf);
init_random_keys(dataset, loop_count, 0xabcdabcd);
}
static void insert_test(void)
{
for (size_t i = 0; i < loop_count; i++)
{
struct rt_varea *varea;
varea = &_varea_buf[i];
varea->start = (void *)(uintptr_t)dataset[i];
varea->size = 1;
_aspace_bst_insert(&aspace, varea);
}
}
static void search_test(void)
{
for (size_t i = 0; i < loop_count; i++)
{
void *start = (void *)(uintptr_t)dataset[i];
struct rt_varea *varea;
varea = _aspace_bst_search(&aspace, start);
assert(varea);
assert(varea->start == start);
}
}
static void delete_test(void)
{
for (size_t i = 0; i < loop_count; i++)
{
void *start = (void *)(uintptr_t)dataset[i];
struct rt_varea *varea;
varea = _aspace_bst_search(&aspace, start);
_aspace_bst_remove(&aspace, varea);
}
}
static void cleanup(void)
{
free(dataset);
free(_varea_buf);
}
int main(int argc, char *argv[])
{
if (argc == 2)
{
rt_sscanf(argv[1], "%d", &loop_count);
}
else
{
loop_count = 1000;
}
puts("Benchmark");
printf("looping times: %d\n", loop_count);
init_test();
int endurance;
STOPWATCH(insert_test, endurance);
printf("Insertion: %d ms\n", endurance);
randomize(dataset, loop_count);
STOPWATCH(search_test, endurance);
printf("Search: %d ms\n", endurance);
randomize(dataset, loop_count);
STOPWATCH(delete_test, endurance);
printf("Delete: %d ms\n", endurance);
cleanup();
puts("Benchmark exit");
return 0;
}

View File

@ -0,0 +1,516 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-01 aozima the first version.
* 2012-02-11 aozima add multiple sector speed test.
* 2012-05-27 aozima use rt_deice API.
*/
#include <rtthread.h>
/* calculate speed */
static void calculate_speed_print(rt_uint32_t speed)
{
rt_uint32_t k,m;
k = speed/1024UL;
if( k )
{
m = k/1024UL;
if( m )
{
rt_kprintf("%d.%dMbyte/s",m,k%1024UL*100/1024UL);
}
else
{
rt_kprintf("%d.%dKbyte/s",k,speed%1024UL*100/1024UL);
}
}
else
{
rt_kprintf("%dbyte/s",speed);
}
}
static rt_err_t _block_device_test(rt_device_t device)
{
rt_err_t result;
struct rt_device_blk_geometry geometry;
rt_uint8_t * read_buffer = RT_NULL;
rt_uint8_t * write_buffer = RT_NULL;
rt_kprintf("\r\n");
if( (device->flag & RT_DEVICE_FLAG_RDWR) == RT_DEVICE_FLAG_RDWR )
{
// device can read and write.
// step 1: open device
result = rt_device_open(device,RT_DEVICE_FLAG_RDWR);
if( result != RT_EOK )
{
return result;
}
// step 2: get device info
rt_memset(&geometry, 0, sizeof(geometry));
result = rt_device_control(device,
RT_DEVICE_CTRL_BLK_GETGEOME,
&geometry);
if( result != RT_EOK )
{
rt_kprintf("device : %s cmd RT_DEVICE_CTRL_BLK_GETGEOME failed.\r\n");
return result;
}
rt_kprintf("device info:\r\n");
rt_kprintf("sector size : %d byte\r\n", geometry.bytes_per_sector);
rt_kprintf("sector count : %d \r\n", geometry.sector_count);
rt_kprintf("block size : %d byte\r\n", geometry.block_size);
rt_kprintf("\r\n");
read_buffer = rt_malloc(geometry.bytes_per_sector);
if( read_buffer == RT_NULL )
{
rt_kprintf("no memory for read_buffer!\r\n");
goto __return;
}
write_buffer = rt_malloc(geometry.bytes_per_sector);
if( write_buffer == RT_NULL )
{
rt_kprintf("no memory for write_buffer!\r\n");
goto __return;
}
/* step 3: R/W test */
{
rt_uint32_t i, err_count, sector_no;
rt_uint8_t * data_point;
i = rt_device_read(device, 0, read_buffer, 1);
if(i != 1)
{
rt_kprintf("read device :%s ", device->parent.name);
rt_kprintf("the first sector failed.\r\n");
goto __return;
}
data_point = write_buffer;
for(i=0; i<geometry.bytes_per_sector; i++)
{
*data_point++ = (rt_uint8_t)i;
}
/* write first sector */
sector_no = 0;
data_point = write_buffer;
*data_point++ = (rt_uint8_t)sector_no;
i = rt_device_write(device, sector_no, write_buffer,1);
if( i != 1 )
{
rt_kprintf("read the first sector success!\r\n");
rt_kprintf("but write device :%s ", device->parent.name);
rt_kprintf("the first sector failed.\r\n");
rt_kprintf("maybe readonly!\r\n");
goto __return;
}
/* write the second sector */
sector_no = 1;
data_point = write_buffer;
*data_point++ = (rt_uint8_t)sector_no;
i = rt_device_write(device,sector_no,write_buffer,1);
if( i != 1 )
{
rt_kprintf("write device :%s ",device->parent.name);
rt_kprintf("the second sector failed.\r\n");
goto __return;
}
/* write the end sector */
sector_no = geometry.sector_count-1;
data_point = write_buffer;
*data_point++ = (rt_uint8_t)sector_no;
i = rt_device_write(device,sector_no,write_buffer,1);
if( i != 1 )
{
rt_kprintf("write device :%s ",device->parent.name);
rt_kprintf("the end sector failed.\r\n");
goto __return;
}
/* verify first sector */
sector_no = 0;
i = rt_device_read(device,sector_no,read_buffer,1);
if( i != 1 )
{
rt_kprintf("read device :%s ",device->parent.name);
rt_kprintf("the first sector failed.\r\n");
goto __return;
}
err_count = 0;
data_point = read_buffer;
if( (*data_point++) != (rt_uint8_t)sector_no)
{
err_count++;
}
for(i=1; i<geometry.bytes_per_sector; i++)
{
if( (*data_point++) != (rt_uint8_t)i )
{
err_count++;
}
}
if( err_count > 0 )
{
rt_kprintf("verify device :%s ",device->parent.name);
rt_kprintf("the first sector failed.\r\n");
goto __return;
}
/* verify sector sector */
sector_no = 1;
i = rt_device_read(device,sector_no,read_buffer,1);
if( i != 1 )
{
rt_kprintf("read device :%s ",device->parent.name);
rt_kprintf("the second sector failed.\r\n");
goto __return;
}
err_count = 0;
data_point = read_buffer;
if( (*data_point++) != (rt_uint8_t)sector_no)
{
err_count++;
}
for(i=1; i<geometry.bytes_per_sector; i++)
{
if( (*data_point++) != (rt_uint8_t)i )
{
err_count++;
}
}
if( err_count > 0 )
{
rt_kprintf("verify device :%s ",device->parent.name);
rt_kprintf("the second sector failed.\r\n");
goto __return;
}
/* verify the end sector */
sector_no = geometry.sector_count-1;
i = rt_device_read(device,sector_no,read_buffer,1);
if( i != 1 )
{
rt_kprintf("read device :%s ",device->parent.name);
rt_kprintf("the end sector failed.\r\n");
goto __return;
}
err_count = 0;
data_point = read_buffer;
if( (*data_point++) != (rt_uint8_t)sector_no)
{
err_count++;
}
for(i=1; i<geometry.bytes_per_sector; i++)
{
if( (*data_point++) != (rt_uint8_t)i )
{
err_count++;
}
}
if( err_count > 0 )
{
rt_kprintf("verify device :%s ",device->parent.name);
rt_kprintf("the end sector failed.\r\n");
goto __return;
}
rt_kprintf("device R/W test pass!\r\n");
} /* step 3: I/O R/W test */
rt_kprintf("\r\nRT_TICK_PER_SECOND:%d\r\n", RT_TICK_PER_SECOND);
// step 4: continuous single sector speed test
{
rt_uint32_t tick_start,tick_end;
rt_uint32_t i;
rt_kprintf("\r\ncontinuous single sector speed test:\r\n");
if( geometry.sector_count < 10 )
{
rt_kprintf("device sector_count < 10, speed test abort!\r\n");
}
else
{
unsigned int sector;
// sign sector write
rt_kprintf("write: ");
sector = 0;
tick_start = rt_tick_get();
for(i=0; i<200; i++)
{
sector += rt_device_write(device, i, read_buffer, 1);
if((i != 0) && ((i%4) == 0) )
{
if(sector < 4)
{
rt_kprintf("#");
}
else
{
rt_kprintf("<");
}
sector = 0;
}
}
tick_end = rt_tick_get();
rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end);
calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
rt_kprintf("\r\n");
// sign sector read
rt_kprintf("read : ");
sector = 0;
tick_start = rt_tick_get();
for(i=0; i<200; i++)
{
sector += rt_device_read(device, i, read_buffer, 1);
if((i != 0) && ((i%4) == 0) )
{
if(sector < 4)
{
rt_kprintf("#");
}
else
{
rt_kprintf(">");
}
sector = 0;
}
}
tick_end = rt_tick_get();
rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end);
calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
rt_kprintf("\r\n");
}
}// step 4: speed test
// step 5: random single sector speed test
{
rt_uint32_t tick_start,tick_end;
rt_uint32_t i;
rt_kprintf("\r\nrandom single sector speed test:\r\n");
if( geometry.sector_count < 10 )
{
rt_kprintf("device sector_count < 10, speed test abort!\r\n");
}
else
{
unsigned int sector;
// sign sector write
rt_kprintf("write: ");
sector = 0;
tick_start = rt_tick_get();
for(i=0; i<200; i++)
{
sector += rt_device_write(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1);
if((i != 0) && ((i%4) == 0) )
{
if(sector < 4)
{
rt_kprintf("#");
}
else
{
rt_kprintf("<");
}
sector = 0;
}
}
tick_end = rt_tick_get();
rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end);
calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
rt_kprintf("\r\n");
// sign sector read
rt_kprintf("read : ");
sector = 0;
tick_start = rt_tick_get();
for(i=0; i<200; i++)
{
sector += rt_device_read(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1);
if((i != 0) && ((i%4) == 0) )
{
if(sector < 4)
{
rt_kprintf("#");
}
else
{
rt_kprintf(">");
}
sector = 0;
}
}
tick_end = rt_tick_get();
rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end);
calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
rt_kprintf("\r\n");
}
}// step 4: speed test
/* step 6: multiple sector speed test */
{
rt_uint8_t * multiple_buffer;
rt_uint8_t * ptr;
rt_uint32_t tick_start,tick_end;
rt_uint32_t sector,i;
rt_kprintf("\r\nmultiple sector speed test\r\n");
for(sector=2; sector<256; sector=sector*2)
{
multiple_buffer = rt_malloc(geometry.bytes_per_sector * sector);
if(multiple_buffer == RT_NULL)
{
rt_kprintf("no memory for %d sector! multiple sector speed test abort!\r\n", sector);
break;
}
rt_memset(multiple_buffer, sector, geometry.bytes_per_sector * sector);
rt_kprintf("write: ");
tick_start = rt_tick_get();
for(i=0; i<10; i++)
{
rt_size_t n;
n = rt_device_write(device, 50, multiple_buffer, sector);
if(n == sector)
{
rt_kprintf("<");
}
else
{
rt_kprintf("#");
}
}
tick_end = rt_tick_get();
rt_kprintf("\r\n");
rt_kprintf("multiple write %d sector speed : ", sector);
calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) );
rt_kprintf("\r\n");
rt_memset(multiple_buffer, ~sector, geometry.bytes_per_sector * sector);
rt_kprintf("read : ");
tick_start = rt_tick_get();
for(i=0; i<10; i++)
{
rt_size_t n;
n = rt_device_read(device, 50, multiple_buffer, sector);
if(n == sector)
{
rt_kprintf(">");
}
else
{
rt_kprintf("#");
}
}
tick_end = rt_tick_get();
rt_kprintf("\r\n");
rt_kprintf("multiple read %d sector speed : ", sector);
calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) );
ptr = multiple_buffer;
for(i=0; i<geometry.bytes_per_sector * sector; i++)
{
if(*ptr != sector)
{
rt_kprintf(" but data verify fail!");
break;
}
ptr++;
}
rt_kprintf("\r\n\r\n");
rt_free(multiple_buffer);
}
} /* step 5: multiple sector speed test */
rt_device_close(device);
return RT_EOK;
}// device can read and write.
else
{
// device read only
rt_device_close(device);
return RT_EOK;
}// device read only
__return:
if( read_buffer != RT_NULL )
{
rt_free(read_buffer);
}
if( write_buffer != RT_NULL )
{
rt_free(write_buffer);
}
rt_device_close(device);
return -RT_ERROR;
}
int device_test(const char * device_name)
{
rt_device_t device = RT_NULL;
// step 1:find device
device = rt_device_find(device_name);
if( device == RT_NULL)
{
rt_kprintf("device %s: not found!\r\n", device_name);
return -RT_ERROR;
}
// step 2:init device
if (!(device->flag & RT_DEVICE_FLAG_ACTIVATED))
{
rt_err_t result;
result = rt_device_init(device);
if (result != RT_EOK)
{
rt_kprintf("To initialize device:%s failed. The error code is %d\r\n",
device->parent.name, result);
return result;
}
else
{
device->flag |= RT_DEVICE_FLAG_ACTIVATED;
}
}
// step 3: device test
switch( device->type )
{
case RT_Device_Class_Block :
rt_kprintf("block device!\r\n");
return _block_device_test(device);
default:
rt_kprintf("unkown device type : %02X",device->type);
return -RT_ERROR;
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(device_test, e.g: device_test("sd0"));
#endif

View File

@ -0,0 +1,412 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry.h (part 1 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
* Siemens AG, AUT E 51
* Postfach 3220
* 8520 Erlangen
* Germany (West)
* Phone: [+49]-9131-7-20330
* (8-17 Central European Time)
* Usenet: ..!mcsun!unido!estevax!weicker
*
* Original Version (in Ada) published in
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
* pp. 1013 - 1030, together with the statistics
* on which the distribution of statements etc. is based.
*
* In this C version, the following C library functions are used:
* - strcpy, strcmp (inside the measurement loop)
* - printf, scanf (outside the measurement loop)
* In addition, Berkeley UNIX system calls "times ()" or "time ()"
* are used for execution time measurement. For measurements
* on other systems, these calls have to be changed.
*
* Collection of Results:
* Reinhold Weicker (address see above) and
*
* Rick Richardson
* PC Research. Inc.
* 94 Apple Orchard Drive
* Tinton Falls, NJ 07724
* Phone: (201) 389-8963 (9-17 EST)
* Usenet: ...!uunet!pcrat!rick
*
* Please send results to Rick Richardson and/or Reinhold Weicker.
* Complete information should be given on hardware and software used.
* Hardware information includes: Machine type, CPU, type and size
* of caches; for microprocessors: clock frequency, memory speed
* (number of wait states).
* Software information includes: Compiler (and runtime library)
* manufacturer and version, compilation switches, OS version.
* The Operating System version may give an indication about the
* compiler; Dhrystone itself performs no OS calls in the measurement loop.
*
* The complete output generated by the program should be mailed
* such that at least some checks for correctness can be made.
*
***************************************************************************
*
* History: This version C/2.1 has been made for two reasons:
*
* 1) There is an obvious need for a common C version of
* Dhrystone, since C is at present the most popular system
* programming language for the class of processors
* (microcomputers, minicomputers) where Dhrystone is used most.
* There should be, as far as possible, only one C version of
* Dhrystone such that results can be compared without
* restrictions. In the past, the C versions distributed
* by Rick Richardson (Version 1.1) and by Reinhold Weicker
* had small (though not significant) differences.
*
* 2) As far as it is possible without changes to the Dhrystone
* statistics, optimizing compilers should be prevented from
* removing significant statements.
*
* This C version has been developed in cooperation with
* Rick Richardson (Tinton Falls, NJ), it incorporates many
* ideas from the "Version 1.1" distributed previously by
* him over the UNIX network Usenet.
* I also thank Chaim Benedelac (National Semiconductor),
* David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
* for their help with comments on earlier versions of the
* benchmark.
*
* Changes: In the initialization part, this version follows mostly
* Rick Richardson's version distributed via Usenet, not the
* version distributed earlier via floppy disk by Reinhold Weicker.
* As a concession to older compilers, names have been made
* unique within the first 8 characters.
* Inside the measurement loop, this version follows the
* version previously distributed by Reinhold Weicker.
*
* At several places in the benchmark, code has been added,
* but within the measurement loop only in branches that
* are not executed. The intention is that optimizing compilers
* should be prevented from moving code out of the measurement
* loop, or from removing code altogether. Since the statements
* that are executed within the measurement loop have NOT been
* changed, the numbers defining the "Dhrystone distribution"
* (distribution of statements, operand types and locality)
* still hold. Except for sophisticated optimizing compilers,
* execution times for this version should be the same as
* for previous versions.
*
* Since it has proven difficult to subtract the time for the
* measurement loop overhead in a correct way, the loop check
* has been made a part of the benchmark. This does have
* an impact - though a very minor one - on the distribution
* statistics which have been updated for this version.
*
* All changes within the measurement loop are described
* and discussed in the companion paper "Rationale for
* Dhrystone version 2".
*
* Because of the self-imposed limitation that the order and
* distribution of the executed statements should not be
* changed, there are still cases where optimizing compilers
* may not generate code for some statements. To a certain
* degree, this is unavoidable for small synthetic benchmarks.
* Users of the benchmark are advised to check code listings
* whether code is generated for all statements of Dhrystone.
*
* Version 2.1 is identical to version 2.0 distributed via
* the UNIX network Usenet in March 1988 except that it corrects
* some minor deficiencies that were found by users of version 2.0.
* The only change within the measurement loop is that a
* non-executed "else" part was added to the "if" statement in
* Func_3, and a non-executed "else" part removed from Proc_3.
*
***************************************************************************
*
* Defines: The following "Defines" are possible:
* -DREG=register (default: Not defined)
* As an approximation to what an average C programmer
* might do, the "register" storage class is applied
* (if enabled by -DREG=register)
* - for local variables, if they are used (dynamically)
* five or more times
* - for parameters if they are used (dynamically)
* six or more times
* Note that an optimal "register" strategy is
* compiler-dependent, and that "register" declarations
* do not necessarily lead to faster execution.
* -DNOSTRUCTASSIGN (default: Not defined)
* Define if the C compiler does not support
* assignment of structures.
* -DNOENUMS (default: Not defined)
* Define if the C compiler does not support
* enumeration types.
* -DTIMES (default)
* -DTIME
* The "times" function of UNIX (returning process times)
* or the "time" function (returning wallclock time)
* is used for measurement.
* For single user machines, "time ()" is adequate. For
* multi-user machines where you cannot get single-user
* access, use the "times ()" function. If you have
* neither, use a stopwatch in the dead of night.
* "printf"s are provided marking the points "Start Timer"
* and "Stop Timer". DO NOT use the UNIX "time(1)"
* command, as this will measure the total time to
* run this program, which will (erroneously) include
* the time to allocate storage (malloc) and to perform
* the initialization.
* -DHZ=nnn
* In Berkeley UNIX, the function "times" returns process
* time in 1/HZ seconds, with HZ = 60 for most systems.
* CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
* A VALUE.
*
***************************************************************************
*
* Compilation model and measurement (IMPORTANT):
*
* This C version of Dhrystone consists of three files:
* - dhry.h (this file, containing global definitions and comments)
* - dhry_1.c (containing the code corresponding to Ada package Pack_1)
* - dhry_2.c (containing the code corresponding to Ada package Pack_2)
*
* The following "ground rules" apply for measurements:
* - Separate compilation
* - No procedure merging
* - Otherwise, compiler optimizations are allowed but should be indicated
* - Default results are those without register declarations
* See the companion paper "Rationale for Dhrystone Version 2" for a more
* detailed discussion of these ground rules.
*
* For 16-Bit processors (e.g. 80186, 80286), times for all compilation
* models ("small", "medium", "large" etc.) should be given if possible,
* together with a definition of these models for the compiler system used.
*
**************************************************************************
*
* Dhrystone (C version) statistics:
*
* [Comment from the first distribution, updated for version 2.
* Note that because of language differences, the numbers are slightly
* different from the Ada version.]
*
* The following program contains statements of a high level programming
* language (here: C) in a distribution considered representative:
*
* assignments 52 (51.0 %)
* control statements 33 (32.4 %)
* procedure, function calls 17 (16.7 %)
*
* 103 statements are dynamically executed. The program is balanced with
* respect to the three aspects:
*
* - statement type
* - operand type
* - operand locality
* operand global, local, parameter, or constant.
*
* The combination of these three aspects is balanced only approximately.
*
* 1. Statement Type:
* ----------------- number
*
* V1 = V2 9
* (incl. V1 = F(..)
* V = Constant 12
* Assignment, 7
* with array element
* Assignment, 6
* with record component
* --
* 34 34
*
* X = Y +|-|"&&"|"|" Z 5
* X = Y +|-|"==" Constant 6
* X = X +|- 1 3
* X = Y *|/ Z 2
* X = Expression, 1
* two operators
* X = Expression, 1
* three operators
* --
* 18 18
*
* if .... 14
* with "else" 7
* without "else" 7
* executed 3
* not executed 4
* for ... 7 | counted every time
* while ... 4 | the loop condition
* do ... while 1 | is evaluated
* switch ... 1
* break 1
* declaration with 1
* initialization
* --
* 34 34
*
* P (...) procedure call 11
* user procedure 10
* library procedure 1
* X = F (...)
* function call 6
* user function 5
* library function 1
* --
* 17 17
* ---
* 103
*
* The average number of parameters in procedure or function calls
* is 1.82 (not counting the function values as implicit parameters).
*
*
* 2. Operators
* ------------
* number approximate
* percentage
*
* Arithmetic 32 50.8
*
* + 21 33.3
* - 7 11.1
* * 3 4.8
* / (int div) 1 1.6
*
* Comparison 27 42.8
*
* == 9 14.3
* /= 4 6.3
* > 1 1.6
* < 3 4.8
* >= 1 1.6
* <= 9 14.3
*
* Logic 4 6.3
*
* && (AND-THEN) 1 1.6
* | (OR) 1 1.6
* ! (NOT) 2 3.2
*
* -- -----
* 63 100.1
*
*
* 3. Operand Type (counted once per operand reference):
* ---------------
* number approximate
* percentage
*
* Integer 175 72.3 %
* Character 45 18.6 %
* Pointer 12 5.0 %
* String30 6 2.5 %
* Array 2 0.8 %
* Record 2 0.8 %
* --- -------
* 242 100.0 %
*
* When there is an access path leading to the final operand (e.g. a record
* component), only the final data type on the access path is counted.
*
*
* 4. Operand Locality:
* -------------------
* number approximate
* percentage
*
* local variable 114 47.1 %
* global variable 22 9.1 %
* parameter 45 18.6 %
* value 23 9.5 %
* reference 22 9.1 %
* function result 6 2.5 %
* constant 55 22.7 %
* --- -------
* 242 100.0 %
*
*
* The program does not compute anything meaningful, but it is syntactically
* and semantically correct. All variables have a value assigned to them
* before they are used as a source operand.
*
* There has been no explicit effort to account for the effects of a
* cache, or to balance the use of long or short displacements for code or
* data.
*
***************************************************************************
*/
/* Compiler and system dependent definitions: */
#define Mic_secs_Per_Second 1000000.0
/* Berkeley UNIX C returns process times in seconds/HZ */
#ifdef NOSTRUCTASSIGN
#define structassign(d, s) memcpy(&(d), &(s), sizeof(d))
#else
#define structassign(d, s) d = s
#endif
#ifdef NOENUM
#define Ident_1 0
#define Ident_2 1
#define Ident_3 2
#define Ident_4 3
#define Ident_5 4
typedef int Enumeration;
#else
typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
Enumeration;
#endif
/* for boolean and enumeration types in Ada, Pascal */
/* General definitions: */
// #include <stdio.h>
/* for strcpy, strcmp */
#include <rtthread.h>
#define Null 0
/* Value of a Null pointer */
#define true 1
#define false 0
typedef int One_Thirty;
typedef int One_Fifty;
typedef char Capital_Letter;
typedef int Boolean;
typedef char Str_30 [31];
typedef int Arr_1_Dim [50];
typedef int Arr_2_Dim [50] [50];
typedef struct record
{
struct record *Ptr_Comp;
Enumeration Discr;
union {
struct {
Enumeration Enum_Comp;
int Int_Comp;
char Str_Comp [31];
} var_1;
struct {
Enumeration E_Comp_2;
char Str_2_Comp [31];
} var_2;
struct {
char Ch_1_Comp;
char Ch_2_Comp;
} var_3;
} variant;
} Rec_Type, *Rec_Pointer;

View File

@ -0,0 +1,349 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_1.c (part 2 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#define NUMBER_OF_RUNS 1000000
#include "dhry.h"
#define printf rt_kprintf
/* Global Variables: */
Rec_Pointer Ptr_Glob,
Next_Ptr_Glob;
int Int_Glob;
Boolean Bool_Glob;
char Ch_1_Glob,
Ch_2_Glob;
int Arr_1_Glob [50];
int Arr_2_Glob [50] [50];
Enumeration Func_1 ();
/* forward declaration necessary since Enumeration may not simply be int */
#ifndef REG
Boolean Reg = false;
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#else
Boolean Reg = true;
#endif
/* variables for time measurement: */
float Begin_Time,
End_Time,
User_Time;
float Microseconds,
Dhrystones_Per_Second;
/* end of variables for time measurement */
void dhry_test(void)
/*****/
/* main program, corresponds to procedures */
/* Main and Proc_0 in the Ada version */
{
One_Fifty Int_1_Loc;
REG One_Fifty Int_2_Loc;
One_Fifty Int_3_Loc;
REG char Ch_Index;
Enumeration Enum_Loc;
Str_30 Str_1_Loc;
Str_30 Str_2_Loc;
REG int Run_Index;
REG int Number_Of_Runs;
/* Initializations */
Next_Ptr_Glob = (Rec_Pointer) rt_malloc (sizeof (Rec_Type));
Ptr_Glob = (Rec_Pointer) rt_malloc (sizeof (Rec_Type));
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
Ptr_Glob->Discr = Ident_1;
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
Ptr_Glob->variant.var_1.Int_Comp = 40;
rt_strncpy (Ptr_Glob->variant.var_1.Str_Comp,
"DHRYSTONE PROGRAM, SOME STRING", sizeof(Ptr_Glob->variant.var_1.Str_Comp));
rt_strncpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING", sizeof(Str_1_Loc));
Arr_2_Glob [8][7] = 10;
/* Was missing in published program. Without this statement, */
/* Arr_2_Glob [8][7] would have an undefined value. */
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
/* overflow may occur for this array element. */
printf ("\n");
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
printf ("\n");
if (Reg)
{
printf ("Program compiled with 'register' attribute\n");
printf ("\n");
}
else
{
printf ("Program compiled without 'register' attribute\n");
printf ("\n");
}
printf ("Please give the number of runs through the benchmark: ");
Number_Of_Runs = NUMBER_OF_RUNS;
printf ("%d\n", Number_Of_Runs);
printf ("\n");
printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
/***************/
/* Start timer */
/***************/
// Add your timer initializing code here
Begin_Time = rt_tick_get(); /* get start tick */
for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
{
Proc_5();
Proc_4();
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
Int_1_Loc = 2;
Int_2_Loc = 3;
rt_strncpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING", sizeof(Str_2_Loc));
Enum_Loc = Ident_2;
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
/* Bool_Glob == 1 */
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
{
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
/* Int_3_Loc == 7 */
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
/* Int_3_Loc == 7 */
Int_1_Loc += 1;
} /* while */
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
/* Int_Glob == 5 */
Proc_1 (Ptr_Glob);
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
/* loop body executed twice */
{
if (Enum_Loc == Func_1 (Ch_Index, 'C'))
/* then, not executed */
{
Proc_6 (Ident_1, &Enum_Loc);
rt_strncpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING", sizeof(Str_2_Loc));
Int_2_Loc = Run_Index;
Int_Glob = Run_Index;
}
}
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Int_2_Loc = Int_2_Loc * Int_1_Loc;
Int_1_Loc = Int_2_Loc / Int_3_Loc;
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
Proc_2 (&Int_1_Loc);
/* Int_1_Loc == 5 */
} /* loop "for Run_Index" */
/**************/
/* Stop timer */
/**************/
End_Time = rt_tick_get(); // Get end tick
printf ("Execution ends\n");
printf ("\n");
printf ("Final values of the variables used in the benchmark:\n");
printf ("\n");
printf ("Int_Glob: %d\n", Int_Glob);
printf (" should be: %d\n", 5);
printf ("Bool_Glob: %d\n", Bool_Glob);
printf (" should be: %d\n", 1);
printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
printf (" should be: %c\n", 'A');
printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
printf (" should be: %c\n", 'B');
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
printf (" should be: %d\n", 7);
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
printf (" should be: Number_Of_Runs + 10\n");
printf ("Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent)\n");
printf (" Discr: %d\n", Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 2);
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 17);
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Next_Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent), same as above\n");
printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 1);
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 18);
printf (" Str_Comp: %s\n",
Next_Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Int_1_Loc: %d\n", Int_1_Loc);
printf (" should be: %d\n", 5);
printf ("Int_2_Loc: %d\n", Int_2_Loc);
printf (" should be: %d\n", 13);
printf ("Int_3_Loc: %d\n", Int_3_Loc);
printf (" should be: %d\n", 7);
printf ("Enum_Loc: %d\n", Enum_Loc);
printf (" should be: %d\n", 1);
printf ("Str_1_Loc: %s\n", Str_1_Loc);
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
printf ("Str_2_Loc: %s\n", Str_2_Loc);
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
printf ("\n");
User_Time = (End_Time - Begin_Time) / RT_TICK_PER_SECOND;
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ (float) Number_Of_Runs;
Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
printf ("Microseconds for one run through Dhrystone: ");
printf ("%6d \n", (int)Microseconds);
printf ("Dhrystones per Second: ");
printf ("%6d \n", (int)Dhrystones_Per_Second);
printf ("Dhrystones MIPS: ");
printf ("%6d \n", (int)(Dhrystones_Per_Second / 1757.0));
printf ("\n");
}
Proc_1 (Ptr_Val_Par)
/******************/
REG Rec_Pointer Ptr_Val_Par;
/* executed once */
{
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
/* == Ptr_Glob_Next */
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
/* corresponds to "rename" in Ada, "with" in Pascal */
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
Next_Record->variant.var_1.Int_Comp
= Ptr_Val_Par->variant.var_1.Int_Comp;
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
Proc_3 (&Next_Record->Ptr_Comp);
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
== Ptr_Glob->Ptr_Comp */
if (Next_Record->Discr == Ident_1)
/* then, executed */
{
Next_Record->variant.var_1.Int_Comp = 6;
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
&Next_Record->variant.var_1.Enum_Comp);
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
&Next_Record->variant.var_1.Int_Comp);
}
else /* not executed */
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
} /* Proc_1 */
Proc_2 (Int_Par_Ref)
/******************/
/* executed once */
/* *Int_Par_Ref == 1, becomes 4 */
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Enumeration Enum_Loc;
Int_Loc = *Int_Par_Ref + 10;
do /* executed once */
if (Ch_1_Glob == 'A')
/* then, executed */
{
Int_Loc -= 1;
*Int_Par_Ref = Int_Loc - Int_Glob;
Enum_Loc = Ident_1;
} /* if */
while (Enum_Loc != Ident_1); /* true */
} /* Proc_2 */
Proc_3 (Ptr_Ref_Par)
/******************/
/* executed once */
/* Ptr_Ref_Par becomes Ptr_Glob */
Rec_Pointer *Ptr_Ref_Par;
{
if (Ptr_Glob != Null)
/* then, executed */
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
} /* Proc_3 */
Proc_4 () /* without parameters */
/*******/
/* executed once */
{
Boolean Bool_Loc;
Bool_Loc = Ch_1_Glob == 'A';
Bool_Glob = Bool_Loc | Bool_Glob;
Ch_2_Glob = 'B';
} /* Proc_4 */
Proc_5 () /* without parameters */
/*******/
/* executed once */
{
Ch_1_Glob = 'A';
Bool_Glob = false;
} /* Proc_5 */
/* Procedure for the assignment of structures, */
/* if the C compiler doesn't support this feature */
#ifdef NOSTRUCTASSIGN
memcpy (d, s, l)
register char *d;
register char *s;
register int l;
{
while (l--) *d++ = *s++;
}
#endif
#include <finsh.h>
FINSH_FUNCTION_EXPORT(dhry_test, dhry test);

View File

@ -0,0 +1,192 @@
/*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_2.c (part 3 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************
*/
#include "dhry.h"
#ifndef REG
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#endif
extern int Int_Glob;
extern char Ch_1_Glob;
Proc_6 (Enum_Val_Par, Enum_Ref_Par)
/*********************************/
/* executed once */
/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
Enumeration Enum_Val_Par;
Enumeration *Enum_Ref_Par;
{
*Enum_Ref_Par = Enum_Val_Par;
if (! Func_3 (Enum_Val_Par))
/* then, not executed */
*Enum_Ref_Par = Ident_4;
switch (Enum_Val_Par)
{
case Ident_1:
*Enum_Ref_Par = Ident_1;
break;
case Ident_2:
if (Int_Glob > 100)
/* then */
*Enum_Ref_Par = Ident_1;
else *Enum_Ref_Par = Ident_4;
break;
case Ident_3: /* executed */
*Enum_Ref_Par = Ident_2;
break;
case Ident_4: break;
case Ident_5:
*Enum_Ref_Par = Ident_3;
break;
} /* switch */
} /* Proc_6 */
Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
/**********************************************/
/* executed three times */
/* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
/* Int_Par_Ref becomes 7 */
/* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
/* Int_Par_Ref becomes 17 */
/* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
/* Int_Par_Ref becomes 18 */
One_Fifty Int_1_Par_Val;
One_Fifty Int_2_Par_Val;
One_Fifty *Int_Par_Ref;
{
One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 2;
*Int_Par_Ref = Int_2_Par_Val + Int_Loc;
} /* Proc_7 */
Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
/*********************************************************************/
/* executed once */
/* Int_Par_Val_1 == 3 */
/* Int_Par_Val_2 == 7 */
Arr_1_Dim Arr_1_Par_Ref;
Arr_2_Dim Arr_2_Par_Ref;
int Int_1_Par_Val;
int Int_2_Par_Val;
{
REG One_Fifty Int_Index;
REG One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 5;
Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
Int_Glob = 5;
} /* Proc_8 */
Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val)
/*************************************************/
/* executed three times */
/* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
/* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
/* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
Capital_Letter Ch_1_Par_Val;
Capital_Letter Ch_2_Par_Val;
{
Capital_Letter Ch_1_Loc;
Capital_Letter Ch_2_Loc;
Ch_1_Loc = Ch_1_Par_Val;
Ch_2_Loc = Ch_1_Loc;
if (Ch_2_Loc != Ch_2_Par_Val)
/* then, executed */
return (Ident_1);
else /* not executed */
{
Ch_1_Glob = Ch_1_Loc;
return (Ident_2);
}
} /* Func_1 */
Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
/*************************************************/
/* executed once */
/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
Str_30 Str_1_Par_Ref;
Str_30 Str_2_Par_Ref;
{
REG One_Thirty Int_Loc;
Capital_Letter Ch_Loc;
Int_Loc = 2;
while (Int_Loc <= 2) /* loop body executed once */
if (Func_1 (Str_1_Par_Ref[Int_Loc],
Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
/* then, executed */
{
Ch_Loc = 'A';
Int_Loc += 1;
} /* if, while */
if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
/* then, not executed */
Int_Loc = 7;
if (Ch_Loc == 'R')
/* then, not executed */
return (true);
else /* executed */
{
if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
/* then, not executed */
{
Int_Loc += 7;
Int_Glob = Int_Loc;
return (true);
}
else /* executed */
return (false);
} /* if Ch_Loc */
} /* Func_2 */
Boolean Func_3 (Enum_Par_Val)
/***************************/
/* executed once */
/* Enum_Par_Val == Ident_3 */
Enumeration Enum_Par_Val;
{
Enumeration Enum_Loc;
Enum_Loc = Enum_Par_Val;
if (Enum_Loc == Ident_3)
/* then, executed */
return (true);
else /* not executed */
return (false);
} /* Func_3 */

View File

@ -0,0 +1,297 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-02 aozima the first version.
* 2011-03-17 aozima fix some bug.
* 2011-03-18 aozima to dynamic thread.
*/
#include <rtthread.h>
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
static rt_uint32_t stop_flag = 0;
static rt_thread_t fsrw1_thread = RT_NULL;
static rt_thread_t fsrw2_thread = RT_NULL;
#define fsrw1_fn "/test1.dat"
#define fsrw1_data_len 120 /* Less than 256 */
static void fsrw1_thread_entry(void* parameter)
{
int fd;
int index,length;
rt_uint32_t round;
rt_uint32_t tick_start,tick_end,read_speed,write_speed;
static rt_uint8_t write_data1[fsrw1_data_len];
static rt_uint8_t read_data1[fsrw1_data_len];
round = 1;
while(1)
{
if( stop_flag )
{
rt_kprintf("thread fsrw2 error,thread fsrw1 quit!\r\n");
fsrw1_thread = RT_NULL;
stop_flag = 0;
return;
}
/* creat file */
fd = open(fsrw1_fn, O_WRONLY | O_CREAT | O_TRUNC, 0);
if (fd < 0)
{
rt_kprintf("fsrw1 open file for write failed\n");
stop_flag = 1;
fsrw1_thread = RT_NULL;
return;
}
/* plan write data */
for (index = 0; index < fsrw1_data_len; index ++)
{
write_data1[index] = index;
}
/* write 8000 times */
tick_start = rt_tick_get();
for(index=0; index<8000; index++)
{
length = write(fd, write_data1, fsrw1_data_len);
if (length != fsrw1_data_len)
{
rt_kprintf("fsrw1 write data failed\n");
close(fd);
fsrw1_thread = RT_NULL;
stop_flag = 1;
return;
}
}
tick_end = rt_tick_get();
write_speed = fsrw1_data_len*8000UL*RT_TICK_PER_SECOND/(tick_end-tick_start);
/* close file */
close(fd);
/* open file read only */
fd = open(fsrw1_fn, O_RDONLY, 0);
if (fd < 0)
{
rt_kprintf("fsrw1 open file for read failed\n");
stop_flag = 1;
fsrw1_thread = RT_NULL;
return;
}
/* verify data */
tick_start = rt_tick_get();
for(index=0; index<8000; index++)
{
rt_uint32_t i;
length = read(fd, read_data1, fsrw1_data_len);
if (length != fsrw1_data_len)
{
rt_kprintf("fsrw1 read file failed\r\n");
close(fd);
stop_flag = 1;
fsrw1_thread = RT_NULL;
return;
}
for(i=0; i<fsrw1_data_len; i++)
{
if( read_data1[i] != write_data1[i] )
{
rt_kprintf("fsrw1 data error!\r\n");
close(fd);
stop_flag = 1;
fsrw1_thread = RT_NULL;
return;
}
}
}
tick_end = rt_tick_get();
read_speed = fsrw1_data_len*8000UL*RT_TICK_PER_SECOND/(tick_end-tick_start);
rt_kprintf("thread fsrw1 round %d ",round++);
rt_kprintf("rd:%dbyte/s,wr:%dbyte/s\r\n",read_speed,write_speed);
/* close file */
close(fd);
}
}
#define fsrw2_fn "/test2.dat"
#define fsrw2_data_len 180 /* Less than 256 */
static void fsrw2_thread_entry(void* parameter)
{
int fd;
int index,length;
rt_uint32_t round;
rt_uint32_t tick_start,tick_end,read_speed,write_speed;
static rt_uint8_t write_data2[fsrw2_data_len];
static rt_uint8_t read_data2[fsrw2_data_len];
round = 1;
while(1)
{
if( stop_flag )
{
rt_kprintf("thread fsrw1 error,thread fsrw2 quit!\r\n");
fsrw2_thread = RT_NULL;
stop_flag = 0;
return;
}
/* creat file */
fd = open(fsrw2_fn, O_WRONLY | O_CREAT | O_TRUNC, 0);
if (fd < 0)
{
rt_kprintf("fsrw2 open file for write failed\n");
stop_flag = 1;
fsrw2_thread = RT_NULL;
return;
}
/* plan write data */
for (index = 0; index < fsrw2_data_len; index ++)
{
write_data2[index] = index;
}
/* write 5000 times */
tick_start = rt_tick_get();
for(index=0; index<5000; index++)
{
length = write(fd, write_data2, fsrw2_data_len);
if (length != fsrw2_data_len)
{
rt_kprintf("fsrw2 write data failed\n");
close(fd);
stop_flag = 1;
fsrw2_thread = RT_NULL;
return;
}
}
tick_end = rt_tick_get();
write_speed = fsrw2_data_len*5000UL*RT_TICK_PER_SECOND/(tick_end-tick_start);
/* close file */
close(fd);
/* open file read only */
fd = open(fsrw2_fn, O_RDONLY, 0);
if (fd < 0)
{
rt_kprintf("fsrw2 open file for read failed\n");
stop_flag = 1;
fsrw2_thread = RT_NULL;
return;
}
/* verify data */
tick_start = rt_tick_get();
for(index=0; index<5000; index++)
{
rt_uint32_t i;
length = read(fd, read_data2, fsrw2_data_len);
if (length != fsrw2_data_len)
{
rt_kprintf("fsrw2 read file failed\r\n");
close(fd);
stop_flag = 1;
fsrw2_thread = RT_NULL;
return;
}
for(i=0; i<fsrw2_data_len; i++)
{
if( read_data2[i] != write_data2[i] )
{
rt_kprintf("fsrw2 data error!\r\n");
close(fd);
stop_flag = 1;
fsrw2_thread = RT_NULL;
return;
}
}
}
tick_end = rt_tick_get();
read_speed = fsrw2_data_len*5000UL*RT_TICK_PER_SECOND/(tick_end-tick_start);
rt_kprintf("thread fsrw2 round %d ",round++);
rt_kprintf("rd:%dbyte/s,wr:%dbyte/s\r\n",read_speed,write_speed);
/* close file */
close(fd);
}
}
/** \brief startup filesystem read/write test(multi thread).
*
* \param arg rt_uint32_t [0]startup thread1,[1]startup thread2.
* \return void
*
*/
void fs_test(rt_uint32_t arg)
{
rt_kprintf("arg is : 0x%02X ",arg);
if(arg & 0x01)
{
if( fsrw1_thread != RT_NULL )
{
rt_kprintf("fsrw1_thread already exists!\r\n");
}
else
{
fsrw1_thread = rt_thread_create( "fsrw1",
fsrw1_thread_entry,
RT_NULL,
2048,
RT_THREAD_PRIORITY_MAX-2,
1);
if ( fsrw1_thread != RT_NULL)
{
rt_thread_startup(fsrw1_thread);
}
}
}
if( arg & 0x02)
{
if( fsrw2_thread != RT_NULL )
{
rt_kprintf("fsrw2_thread already exists!\r\n");
}
else
{
fsrw2_thread = rt_thread_create( "fsrw2",
fsrw2_thread_entry,
RT_NULL,
2048,
RT_THREAD_PRIORITY_MAX-2,
1);
if ( fsrw2_thread != RT_NULL)
{
rt_thread_startup(fsrw2_thread);
}
}
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(fs_test, file system R/W test. e.g: fs_test(3));
#endif

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <finsh.h>
#ifdef RT_USING_HWTIMER
#define TIMER "timer0"
static rt_err_t timer_timeout_cb(rt_device_t dev, rt_size_t size)
{
rt_kprintf("enter hardware timer isr\n");
return 0;
}
int hwtimer(void)
{
rt_err_t err;
rt_hwtimerval_t val;
rt_device_t dev = RT_NULL;
rt_tick_t tick;
rt_hwtimer_mode_t mode;
int freq = 10000;
int t = 5;
if ((dev = rt_device_find(TIMER)) == RT_NULL)
{
rt_kprintf("No Device: %s\n", TIMER);
return -1;
}
if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
{
rt_kprintf("Open %s Fail\n", TIMER);
return -1;
}
/* 时间测量 */
/* 计数时钟设置(默认1Mhz或支持的最小计数频率) */
err = rt_device_control(dev, HWTIMER_CTRL_FREQ_SET, &freq);
if (err != RT_EOK)
{
rt_kprintf("Set Freq=%dhz Fail\n", freq);
goto EXIT;
}
/* 周期模式 */
mode = HWTIMER_MODE_PERIOD;
err = rt_device_control(dev, HWTIMER_CTRL_MODE_SET, &mode);
tick = rt_tick_get();
rt_kprintf("Start Timer> Tick: %d\n", tick);
/* 设置定时器超时值并启动定时器 */
val.sec = t;
val.usec = 0;
rt_kprintf("SetTime: Sec %d, Usec %d\n", val.sec, val.usec);
if (rt_device_write(dev, 0, &val, sizeof(val)) != sizeof(val))
{
rt_kprintf("SetTime Fail\n");
goto EXIT;
}
rt_kprintf("Sleep %d sec\n", t);
rt_thread_delay(t*RT_TICK_PER_SECOND);
/* 停止定时器 */
err = rt_device_control(dev, HWTIMER_CTRL_STOP, RT_NULL);
rt_kprintf("Timer Stoped\n");
/* 读取计数 */
rt_device_read(dev, 0, &val, sizeof(val));
rt_kprintf("Read: Sec = %d, Usec = %d\n", val.sec, val.usec);
/* 定时执行回调函数 -- 单次模式 */
/* 设置超时回调函数 */
rt_device_set_rx_indicate(dev, timer_timeout_cb);
/* 单次模式 */
mode = HWTIMER_MODE_PERIOD;
err = rt_device_control(dev, HWTIMER_CTRL_MODE_SET, &mode);
/* 设置定时器超时值并启动定时器 */
val.sec = t;
val.usec = 0;
rt_kprintf("SetTime: Sec %d, Usec %d\n", val.sec, val.usec);
if (rt_device_write(dev, 0, &val, sizeof(val)) != sizeof(val))
{
rt_kprintf("SetTime Fail\n");
goto EXIT;
}
/* 等待回调函数执行 */
rt_thread_delay((t + 1)*RT_TICK_PER_SECOND);
EXIT:
err = rt_device_close(dev);
rt_kprintf("Close %s\n", TIMER);
return err;
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT(hwtimer, "Test hardware timer");
#endif
#endif /* RT_USING_HWTIMER */

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#define printf rt_kprintf
void mem_test(uint32_t address, uint32_t size )
{
uint32_t i;
printf("memtest,address: 0x%08X size: 0x%08X\r\n", address, size);
/**< 8bit test */
{
uint8_t * p_uint8_t = (uint8_t *)address;
for(i=0; i<size/sizeof(uint8_t); i++)
{
*p_uint8_t++ = (uint8_t)i;
}
p_uint8_t = (uint8_t *)address;
for(i=0; i<size/sizeof(uint8_t); i++)
{
if( *p_uint8_t != (uint8_t)i )
{
printf("8bit test fail @ 0x%08X\r\nsystem halt!!!!!",(uint32_t)p_uint8_t);
while(1);
}
p_uint8_t++;
}
printf("8bit test pass!!\r\n");
}
/**< 16bit test */
{
uint16_t * p_uint16_t = (uint16_t *)address;
for(i=0; i<size/sizeof(uint16_t); i++)
{
*p_uint16_t++ = (uint16_t)i;
}
p_uint16_t = (uint16_t *)address;
for(i=0; i<size/sizeof(uint16_t); i++)
{
if( *p_uint16_t != (uint16_t)i )
{
printf("16bit test fail @ 0x%08X\r\nsystem halt!!!!!",(uint32_t)p_uint16_t);
while(1);
}
p_uint16_t++;
}
printf("16bit test pass!!\r\n");
}
/**< 32bit test */
{
uint32_t * p_uint32_t = (uint32_t *)address;
for(i=0; i<size/sizeof(uint32_t); i++)
{
*p_uint32_t++ = (uint32_t)i;
}
p_uint32_t = (uint32_t *)address;
for(i=0; i<size/sizeof(uint32_t); i++)
{
if( *p_uint32_t != (uint32_t)i )
{
printf("32bit test fail @ 0x%08X\r\nsystem halt!!!!!",(uint32_t)p_uint32_t);
while(1);
}
p_uint32_t++;
}
printf("32bit test pass!!\r\n");
}
/**< 32bit Loopback test */
{
uint32_t * p_uint32_t = (uint32_t *)address;
for(i=0; i<size/sizeof(uint32_t); i++)
{
*p_uint32_t = (uint32_t)p_uint32_t;
p_uint32_t++;
}
p_uint32_t = (uint32_t *)address;
for(i=0; i<size/sizeof(uint32_t); i++)
{
if( *p_uint32_t != (uint32_t)p_uint32_t )
{
printf("32bit Loopback test fail @ 0x%08X", (uint32_t)p_uint32_t);
printf(" data:0x%08X \r\n", (uint32_t)*p_uint32_t);
printf("system halt!!!!!",(uint32_t)p_uint32_t);
while(1);
}
p_uint32_t++;
}
printf("32bit Loopback test pass!!\r\n");
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(mem_test, mem_test(0xA0000000, 0x00100000) );
#endif

View File

@ -0,0 +1,345 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/*
* Net Test Utilities for RT-Thread
*/
#include <rtthread.h>
#include <finsh.h>
#include <lwip/api.h>
#include <lwip/sockets.h>
#include <lwip/init.h>
/*
* UDP echo server
*/
#define UDP_ECHO_PORT 7
rt_thread_t udpecho_tid = RT_NULL;
void udpecho_entry(void *parameter)
{
struct netconn *conn;
struct netbuf *buf;
struct ip_addr *addr;
unsigned short port;
conn = netconn_new(NETCONN_UDP);
if(conn == NULL)
{
rt_kprintf("no memory error\n");
return;
}
netconn_bind(conn, IP_ADDR_ANY, 7);
while(1)
{
/* received data to buffer */
#if LWIP_VERSION_MINOR==3U
buf = netconn_recv(conn);
#else
netconn_recv(conn, &buf);
#endif
if(buf == NULL)
{
break;
}
addr = netbuf_fromaddr(buf);
port = netbuf_fromport(buf);
/* send the data to buffer */
netconn_connect(conn, addr, port);
/* reset address, and send to client */
#if LWIP_VERSION_MINOR==3U
buf->addr = RT_NULL;
#else
buf->addr = *IP_ADDR_ANY;
#endif
netconn_send(conn, buf);
/* release buffer */
netbuf_delete(buf);
}
netconn_delete(conn);
}
/*
* UDP socket echo server
*/
#define UDP_SOCKET_ECHO_PORT 700
#define UDP_SOCKET_BUFFER_SIZE 4096
rt_thread_t udpecho_socket_tid = RT_NULL;
void udpecho_socket_entry(void *parameter)
{
int sock;
int bytes_read;
char *recv_data;
rt_uint32_t addr_len;
struct sockaddr_in server_addr, client_addr;
/* allocate the data buffer */
recv_data = rt_malloc(UDP_SOCKET_BUFFER_SIZE);
if (recv_data == RT_NULL)
{
/* no memory yet */
rt_kprintf("no memory\n");
return;
}
/* create a UDP socket */
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
rt_kprintf("create socket error\n");
goto _exit;
}
/* initialize server address */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(UDP_SOCKET_ECHO_PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero),0, sizeof(server_addr.sin_zero));
/* bind socket to server address */
if (bind(sock,(struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
/* bind failed */
rt_kprintf("bind error\n");
goto _exit;
}
addr_len = sizeof(struct sockaddr);
while (1)
{
/* try to receive from UDP socket */
bytes_read = recvfrom(sock, recv_data, UDP_SOCKET_BUFFER_SIZE, 0,
(struct sockaddr *)&client_addr, &addr_len);
/* send back */
sendto(sock, recv_data, bytes_read, 0,
(struct sockaddr *)&client_addr, addr_len);
}
_exit:
rt_free(recv_data);
return;
}
/*
* TCP echo server
*/
#define TCP_ECHO_PORT 7
rt_thread_t tcpecho_tid = RT_NULL;
void tcpecho_entry(void *parameter)
{
struct netconn *conn, *newconn;
err_t err;
/* Create a new connection identifier. */
conn = netconn_new(NETCONN_TCP);
if(conn == NULL)
{
rt_kprintf("no memory error\n");
return;
}
/* Bind connection to well known port number 7. */
netconn_bind(conn, NULL, TCP_ECHO_PORT);
/* Tell connection to go into listening mode. */
netconn_listen(conn);
while(1)
{
/* Grab new connection. */
#if LWIP_VERSION_MINOR==3U
newconn = netconn_accept(conn);
if(newconn != NULL)
#else
err = netconn_accept(conn, &newconn);
if(err == ERR_OK)
#endif
/* Process the new connection. */
{
struct netbuf *buf;
void *data;
u16_t len;
#if LWIP_VERSION_MINOR==3U
while((buf = netconn_recv(newconn)) != NULL)
#else
while((err = netconn_recv(newconn, &buf)) == ERR_OK)
#endif
{
do
{
netbuf_data(buf, &data, &len);
err = netconn_write(newconn, data, len, NETCONN_COPY);
if(err != ERR_OK)
{
break;
}
}while(netbuf_next(buf) >= 0);
netbuf_delete(buf);
}
/* Close connection and discard connection identifier. */
netconn_delete(newconn);
}
}
netconn_delete(conn);
}
/*
* TCP socket echo server
*/
#define TCP_SOCKET_ECHO_PORT 700
#define TCP_SOCKET_BUFFER_SIZE 4096
rt_thread_t tcpecho_socket_tid = RT_NULL;
void tcpecho_socket_entry(void *parameter)
{
char *recv_data;
rt_uint32_t sin_size;
int sock = -1, connected, bytes_received;
struct sockaddr_in server_addr, client_addr;
recv_data = rt_malloc(TCP_SOCKET_BUFFER_SIZE);
if (recv_data == RT_NULL)
{
rt_kprintf("no memory\n");
return;
}
/* create a TCP socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
rt_kprintf("create socket error\n");
goto _exit;
}
/* initialize server address */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(TCP_SOCKET_ECHO_PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero),0, sizeof(server_addr.sin_zero));
/* bind to server address */
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
rt_kprintf("bind address failed\n");
goto _exit;
}
/* listen */
if (listen(sock, 5) == -1)
{
rt_kprintf("listen error\n");
goto _exit;
}
sin_size = sizeof(struct sockaddr_in);
while(1)
{
/* accept client connected */
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
if (connected > 0)
{
int timeout;
/* set timeout option */
timeout = 5000; /* 5second */
setsockopt(connected, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
/* handle this client */
while (1)
{
/* receive data from this connection */
bytes_received = recv(connected,recv_data, TCP_SOCKET_BUFFER_SIZE, 0);
if (bytes_received <= 0)
{
rt_kprintf("close client connection, errno: %d\n", rt_get_errno());
/* connection closed. */
lwip_close(connected);
break;
}
/* send data to client */
send(connected, recv_data, bytes_received, 0);
}
}
}
_exit:
/* close socket */
if (sock != -1) lwip_close(sock);
rt_free(recv_data);
return;
}
/*
* NetIO TCP server
*/
/* network test utilities entry */
void net_test(void)
{
/* start UDP echo server */
if (udpecho_tid == RT_NULL)
{
udpecho_tid = rt_thread_create("uecho",
udpecho_entry,
RT_NULL,
512,
RT_THREAD_PRIORITY_MAX/2, 5);
if (udpecho_tid != RT_NULL)
{
rt_thread_startup(udpecho_tid);
}
}
if (udpecho_socket_tid == RT_NULL)
{
udpecho_socket_tid = rt_thread_create("uecho_s",
udpecho_socket_entry,
RT_NULL,
512,
RT_THREAD_PRIORITY_MAX/2 + 1, 5);
if (udpecho_socket_tid != RT_NULL)
{
rt_thread_startup(udpecho_socket_tid);
}
}
if (tcpecho_tid == RT_NULL)
{
tcpecho_tid = rt_thread_create("techo",
tcpecho_entry,
RT_NULL,
512,
RT_THREAD_PRIORITY_MAX/2 + 2, 5);
if (tcpecho_tid != RT_NULL)
{
rt_thread_startup(tcpecho_tid);
}
}
if (tcpecho_socket_tid == RT_NULL)
{
tcpecho_socket_tid = rt_thread_create("techo_s",
tcpecho_socket_entry,
RT_NULL,
512,
RT_THREAD_PRIORITY_MAX/2 + 3, 5);
}
if (tcpecho_socket_tid != RT_NULL)
{
rt_thread_startup(tcpecho_socket_tid);
}
}
FINSH_FUNCTION_EXPORT(net_test, network test);

View File

@ -0,0 +1,327 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-31 armink the first version
*/
#include <string.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
static rt_bool_t put_finish = RT_FALSE;
static void put_thread(void *param)
{
rt_rbb_t rbb = (rt_rbb_t)param;
rt_rbb_blk_t block;
rt_uint8_t put_count = 0;
put_finish = RT_FALSE;
while (put_count < 255)
{
if (put_count == 10)
{
put_count = 10;
}
block = rt_rbb_blk_alloc(rbb, rand() % 10 + 1);
if (block)
{
block->buf[0] = put_count++;
rt_rbb_blk_put(block);
}
rt_thread_mdelay(rand() % 10);
}
rt_kprintf("Put block data finish.\n");
put_finish = RT_TRUE;
}
static void get_thread(void *param)
{
rt_rbb_t rbb = (rt_rbb_t)param;
rt_rbb_blk_t block;
rt_uint8_t get_count = 0;
while (get_count < 255)
{
if (get_count == 10)
{
get_count = 10;
}
block = rt_rbb_blk_get(rbb);
if (block)
{
if (block->buf[0] != get_count++)
{
rt_kprintf("Error: get data (times %d) has an error!\n", get_count);
}
rt_rbb_blk_free(rbb, block);
}
else if (put_finish)
{
break;
}
rt_thread_mdelay(rand() % 10);
}
rt_kprintf("Get block data finish.\n");
rt_kprintf("\n====================== rbb dynamic test finish =====================\n");
}
void rbb_test(void)
{
rt_rbb_t rbb;
rt_rbb_blk_t blk1, blk2, blk3, blk4, blk5, blk6, _blk1, _blk2;
rt_size_t i, j, k, req_size, size;
struct rt_rbb_blk_queue blk_queue1;
rt_thread_t thread;
/* create ring block buffer */
rt_kprintf("\n====================== rbb create test =====================\n");
rbb = rt_rbb_create(52, 6);
if (rbb)
{
rt_kprintf("6 blocks in 52 bytes ring block buffer object create success.\n");
}
else
{
rt_kprintf("Test error: 6 blocks in 52 bytes ring block buffer object create failed.\n");
}
/* allocate block */
rt_kprintf("\n====================== rbb alloc test =====================\n");
blk1 = rt_rbb_blk_alloc(rbb, 2);
if (blk1 && blk1->size == 2)
{
memset(blk1->buf, 1, blk1->size);
rt_kprintf("Block1 (2 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block1 (2 bytes) allocate failed.\n");
goto __exit;
}
blk2 = rt_rbb_blk_alloc(rbb, 4);
if (blk2 && blk2->size == 4)
{
memset(blk2->buf, 2, blk2->size);
rt_kprintf("Block2 (4 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block2 (4 bytes) allocate failed.\n");
goto __exit;
}
blk3 = rt_rbb_blk_alloc(rbb, 8);
if (blk3 && blk3->size == 8)
{
memset(blk3->buf, 3, blk3->size);
rt_kprintf("Block3 (8 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block3 (8 bytes) allocate failed.\n");
goto __exit;
}
blk4 = rt_rbb_blk_alloc(rbb, 16);
if (blk4 && blk4->size == 16)
{
memset(blk4->buf, 4, blk4->size);
rt_kprintf("Block4 (16 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block4 (16 bytes) allocate failed.\n");
goto __exit;
}
blk5 = rt_rbb_blk_alloc(rbb, 32);
if (blk5 && blk5->size == 32)
{
memset(blk5->buf, 5, blk5->size);
rt_kprintf("Block5 (32 bytes) allocate success.\n");
}
else
{
rt_kprintf("Block5 (32 bytes) allocate failed.\n");
}
blk5 = rt_rbb_blk_alloc(rbb, 18);
if (blk5 && blk5->size == 18)
{
memset(blk5->buf, 5, blk5->size);
rt_kprintf("Block5 (18 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block5 (18 bytes) allocate failed.\n");
goto __exit;
}
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<- 2 -->|<-- 4 -->|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| blcok1 | block2 | block3 | block4 | block5 | empty |\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| inited | inited | inited | inited | inited | |\n");
/* put block */
rt_kprintf("\n====================== rbb put test =====================\n");
rt_rbb_blk_put(blk1);
rt_rbb_blk_put(blk2);
rt_rbb_blk_put(blk3);
rt_rbb_blk_put(blk4);
rt_rbb_blk_put(blk5);
rt_kprintf("Block1 to block5 put success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<- 2 -->|<-- 4 -->|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| blcok1 | block2 | block3 | block4 | block5 | empty |\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| put | put | put | put | put | |\n");
/* get block */
rt_kprintf("\n====================== rbb get test =====================\n");
_blk1 = rt_rbb_blk_get(rbb);
_blk2 = rt_rbb_blk_get(rbb);
for (i = 0; i < _blk1->size; i++)
{
if (_blk1->buf[i] != 1) break;
}
for (j = 0; j < _blk2->size; j++)
{
if (_blk2->buf[j] != 2) break;
}
if (blk1 == _blk1 && blk2 == _blk2 && i == _blk1->size && j == _blk2->size)
{
rt_kprintf("Block1 and block2 get success.\n");
}
else
{
rt_kprintf("Test error: block1 and block2 get failed.\n");
goto __exit;
}
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<- 2 -->|<-- 4 -->|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| blcok1 | block2 | block3 | block4 | block5 | empty |\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| get | get | put | put | put | |\n");
/* free block */
rt_kprintf("\n====================== rbb free test =====================\n");
rt_rbb_blk_free(rbb, blk2);
rt_kprintf("Block2 free success.\n");
rt_rbb_blk_free(rbb, blk1);
rt_kprintf("Block1 free success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<------- 6 ------>|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+------------------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| empty2 | block3 | block4 | block5 | empty1 |\n");
rt_kprintf("+------------------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| | put | put | put | |\n");
blk6 = rt_rbb_blk_alloc(rbb, 5);
if (blk6)
{
rt_kprintf("Block6 (5 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block6 (5 bytes) allocate failed.\n");
goto __exit;
}
rt_rbb_blk_put(blk6);
rt_kprintf("Block6 put success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<--- 5 ---->|< 1 >|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| block6 |empty| block3 | block4 | block5 | fragment |\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| put | | put | put | put | |\n");
/* get block queue */
rt_kprintf("\n====================== rbb block queue get test =====================\n");
req_size = rt_rbb_next_blk_queue_len(rbb) + 5;
size = rt_rbb_blk_queue_get(rbb, req_size, &blk_queue1);
i = j = k = 0;
for (; i < blk3->size; i++)
{
if (rt_rbb_blk_queue_buf(&blk_queue1)[i] != 3) break;
}
for (; j < blk4->size; j++)
{
if (rt_rbb_blk_queue_buf(&blk_queue1)[i + j] != 4) break;
}
for (; k < blk5->size; k++)
{
if (rt_rbb_blk_queue_buf(&blk_queue1)[i + j + k] != 5) break;
}
if (size && size == 42 && rt_rbb_blk_queue_len(&blk_queue1) == 42 && k == blk5->size)
{
rt_kprintf("Block queue (request %d bytes, actual %d) get success.\n", req_size, size);
}
else
{
rt_kprintf("Test error: Block queue (request %d bytes, actual %d) get failed.\n", req_size, size);
goto __exit;
}
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("| | |<----- block queue1 (42 bytes continuous buffer) ----->| |\n");
rt_kprintf("|<--- 5 ---->|< 1 >|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| block6 |empty| block3 | block4 | block5 | fragment |\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| put | | get | get | get | |\n");
/* free block queue */
rt_kprintf("\n====================== rbb block queue free test =====================\n");
rt_rbb_blk_queue_free(rbb, &blk_queue1);
rt_kprintf("Block queue1 free success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<--- 5 ---->|<--------------------------------- 47 ------------------------------------>|\n");
rt_kprintf("+------------+---------------------------------------------------------------------------+\n");
rt_kprintf("| block6 | empty |\n");
rt_kprintf("+------------+---------------------------------------------------------------------------+\n");
rt_kprintf("| put | |\n");
rt_rbb_blk_free(rbb, blk6);
rt_kprintf("\n====================== rbb static test SUCCESS =====================\n");
rt_kprintf("\n====================== rbb dynamic test =====================\n");
thread = rt_thread_create("rbb_put", put_thread, rbb, 1024, 10, 25);
if (thread)
{
rt_thread_startup(thread);
}
thread = rt_thread_create("rbb_get", get_thread, rbb, 1024, 10, 25);
if (thread)
{
rt_thread_startup(thread);
}
__exit :
rt_rbb_destroy(rbb);
}
MSH_CMD_EXPORT(rbb_test, run ring block buffer testcase)

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-07 ZXY the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
#include <ipc/ringbuffer.h>
#define RING_BUFFER_LEN 8
static struct ringbuffer *rb;
static char *str = "Hello, World new ringbuffer32";
typedef struct rb_example {
rt_uint32_t a;
rt_uint32_t b;
rt_uint32_t c;
} rb_example_t;
int ringbuffer_example(void)
{
rb_example_t data = {
.a = 1,
.b = 2,
};
struct rt_ringbuffer * rb = rt_ringbuffer_create(sizeof(rb_example_t) * 2);
RT_ASSERT(rb != RT_NULL);
rt_kprintf("Put data to ringbuffer, a: %d b: %d size: %d\n", data.a, data.b, sizeof(data));
rt_ringbuffer_put(rb, (rt_uint8_t *)&data, sizeof(data));
rb_example_t recv_data;
rt_size_t recv = rt_ringbuffer_get(rb, (rt_uint8_t *)&recv_data, sizeof(recv_data));
RT_ASSERT(recv == sizeof(recv_data));
rt_kprintf("Get data from ringbuffer, a: %d b: %d size: %d\n", recv_data.a, recv_data.b, sizeof(recv_data));
return 0;
}
MSH_CMD_EXPORT(ringbuffer_example, ringbuffer example);
int ringbuffer_force_example(void)
{
uint8_t test[6] = {1,2,3,4,5,6};
struct rt_ringbuffer * rb;
rb = rt_ringbuffer_create(4);
RT_ASSERT(rb != RT_NULL);
rt_kprintf("Put data to ringbuffer, %d %d %d %d %d %d\n", test[0],test[1],test[2],test[3],test[4],test[5]);
rt_ringbuffer_put_force(rb, (rt_uint8_t *)&test, sizeof(test));
uint8_t recv_data[4]={0};
rt_ringbuffer_get(rb, (rt_uint8_t *)&recv_data, sizeof(test));
rt_kprintf("Get data from ringbuffer, %d %d %d %d\n", recv_data[0],recv_data[1],recv_data[2],recv_data[3]);
rt_kprintf("write mirror: %d read mirror: %d\n", rb->write_mirror,rb->read_mirror);
return 0;
}
MSH_CMD_EXPORT(ringbuffer_force_example, ringbuffer example);
static void consumer_thread_entry(void *arg)
{
char ch;
while (1)
{
if (1 == rt_ringbuffer_getchar(rb, &ch))
{
rt_kprintf("[Consumer] <- %c\n", ch);
}
rt_thread_mdelay(500);
}
}
static void ringbuffer_sample(int argc, char** argv)
{
rt_thread_t tid;
rt_uint16_t i = 0;
rb = rt_ringbuffer_create(RING_BUFFER_LEN);
if (rb == RT_NULL)
{
rt_kprintf("Can't create ringbffer");
return;
}
tid = rt_thread_create("consumer", consumer_thread_entry, RT_NULL,
1024, RT_THREAD_PRIORITY_MAX/3, 20);
if (tid == RT_NULL)
{
rt_ringbuffer_destroy(rb);
}
rt_thread_startup(tid);
while (str[i] != '\0')
{
rt_kprintf("[Producer] -> %c\n", str[i]);
rt_ringbuffer_putchar(rb, str[i++]);
rt_thread_mdelay(500);
}
rt_thread_delete(tid);
rt_ringbuffer_destroy(rb);
}
MSH_CMD_EXPORT(ringbuffer_sample, Start a producer and a consumer with a ringbuffer);

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-01-15 Liu2guang the first version.
*/
#include <rtthread.h>
#include <rtdevice.h>
int rtc_test(void)
{
uint8_t i;
time_t now;
rt_err_t ret = RT_EOK;
rt_kprintf("[RTC Test]RTC Test Start...\n");
rt_thread_delay(RT_TICK_PER_SECOND);
rt_kprintf("[RTC Test]Set RTC 2017-04-01 12:30:46\n");
rt_thread_delay(RT_TICK_PER_SECOND);
ret = set_date(2017, 4, 1);
if(ret != RT_EOK)
{
rt_kprintf("[RTC Test]Set RTC Date failed\n");
return -RT_ERROR;
}
rt_thread_delay(RT_TICK_PER_SECOND);
ret = set_time(12, 30, 46);
if(ret != RT_EOK)
{
rt_kprintf("[RTC Test]Set RTC Time failed\n");
return -RT_ERROR;
}
rt_thread_delay(RT_TICK_PER_SECOND);
for(i = 0; i < 10; i++)
{
rt_kprintf("[RTC Test]Read RTC Date and Time: ");
now = time(RT_NULL);
rt_kprintf("%s\n", ctime(&now));
rt_thread_delay(RT_TICK_PER_SECOND);
}
rt_kprintf("\n");
return RT_EOK;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(rtc_test, rtc driver test. e.g: rtc_test());
MSH_CMD_EXPORT(rtc_test, rtc driver test. e.g: rtc_test());
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-02 armink the first version
*/
#include <stdlib.h>
#include <rtthread.h>
#ifndef ULOG_USING_SYSLOG
#define LOG_TAG "example"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
#else
#include <syslog.h>
#endif /* ULOG_USING_SYSLOG */
void ulog_example(void)
{
int count = 0;
#ifdef ULOG_USING_SYSLOG
openlog("example1", 0, 0);
#endif
while (count++ < 50)
{
#ifndef ULOG_USING_SYSLOG
/* output different level log by LOG_X API */
LOG_D("LOG_D(%d): RT-Thread is an open source IoT operating system from China.", count);
LOG_I("LOG_I(%d): RT-Thread is an open source IoT operating system from China.", count);
LOG_W("LOG_W(%d): RT-Thread is an open source IoT operating system from China.", count);
LOG_E("LOG_E(%d): RT-Thread is an open source IoT operating system from China.", count);
ulog_d("test", "ulog_d(%d): RT-Thread is an open source IoT operating system from China.", count);
ulog_i("test", "ulog_i(%d): RT-Thread is an open source IoT operating system from China.", count);
ulog_w("test", "ulog_w(%d): RT-Thread is an open source IoT operating system from China.", count);
ulog_e("test", "ulog_e(%d): RT-Thread is an open source IoT operating system from China.", count);
#ifdef ULOG_USING_FILTER
if (count == 20)
{
/* Set the global filer level is INFO. All of DEBUG log will stop output */
ulog_global_filter_lvl_set(LOG_LVL_INFO);
/* Set the test tag's level filter's level is ERROR. The DEBUG, INFO, WARNING log will stop output. */
ulog_tag_lvl_filter_set("test", LOG_LVL_ERROR);
}
else if (count == 30)
{
/* Set the example tag's level filter's level is LOG_FILTER_LVL_SILENT, the log enter silent mode. */
ulog_tag_lvl_filter_set("example", LOG_FILTER_LVL_SILENT);
/* Set the test tag's level filter's level is WARNING. The DEBUG, INFO log will stop output. */
ulog_tag_lvl_filter_set("test", LOG_LVL_WARNING);
}
else if (count == 40)
{
/* Set the test tag's level filter's level is LOG_FILTER_LVL_ALL. All level log will resume output. */
ulog_tag_lvl_filter_set("test", LOG_FILTER_LVL_ALL);
/* Set the global filer level is LOG_FILTER_LVL_ALL. All level log will resume output */
ulog_global_filter_lvl_set(LOG_FILTER_LVL_ALL);
}
#endif /* ULOG_USING_FILTER */
#else
/* output different priority log by syslog API */
syslog(LOG_INFO, "syslog(%d) LOG_INFO: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_DEBUG, "syslog(%d) LOG_DEBUG: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_WARNING, "syslog(%d) LOG_WARNING: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_ERR, "syslog(%d) LOG_ERR: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_INFO | LOG_MAIL, "syslog(%d) LOG_INFO | LOG_MAIL: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_DEBUG | LOG_DAEMON, "syslog(%d) LOG_DEBUG | LOG_DAEMON: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_WARNING | LOG_AUTH, "syslog(%d) LOG_WARNING | LOG_AUTH: RT-Thread is an open source IoT operating system from China.", count);
syslog(LOG_ERR | LOG_SYSLOG, "syslog(%d) LOG_ERR | LOG_SYSLOG: RT-Thread is an open source IoT operating system from China.", count);
if (count == 20)
{
/* Set log priority mask. Only output ERR and WARNING log. */
setlogmask(LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
}
else if (count == 40)
{
/* Set log priority mask. The log which level is less than ERROR will stop output. */
setlogmask(LOG_UPTO(LOG_ERR));
}
#endif /* ULOG_USING_SYSLOG */
rt_thread_delay(rt_tick_from_millisecond(rand() % 1000));
}
}
MSH_CMD_EXPORT(ulog_example, run ulog example)

View File

@ -0,0 +1,73 @@
# RT-Thread 测试用例集合
## 简介
为了保证某一部分代码的质量,通常可以通过编写测试用例的方式,验证此代码的功能。为了保证 RT-Thread 相关仓库的代码质量,我们基于 utest 框架搭建了一套简易的自动化测试环境。有兴趣,有精力的小伙伴可以利用这套机制完善自己的代码检查。如果有意愿让社区上更多的小伙伴受益,也可以在提交代码的时候,把对应的测试用例也提交上来。
## 目录结构
| 目录 | 用途 |
| --------- | ------------------------------------------------------------ |
| configs | 配置文件集合每一个目录代表一种功能集合kernel,net等 |
| testcases | 测试用例源代码 |
## 如何贡献
### 1. 编写测试用例
参考已有的测试用例在 [examples\utest\testcases](./testcases) 目录下添加自己的测试用例。测试用例的编写方法参考文档中心[《utest 测试框架》章节](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/utest/utest)。
### 2. 本地测试
1.`bsp\qemu-vexpress-a9` 目录下打开 `menuconfig`,使能对应的测试用例,如下:
```
RT-Thread Utestcases --->
[*] RT-Thread Utestcases
Utest Self Testcase --->
[*] Pass test
```
2. 保存并退出,输入 scons 编译当前 bsp。
3. 输入 .\qemu.bat 运行当前 bsp在 msh 环境下执行 utest_run 命令,验证代码运行是否正常。
```
msh />utest_run
[I/utest] [==========] [ utest ] loop 1/1
[I/utest] [==========] [ utest ] started
[I/utest] [----------] [ testcase ] (testcases.utest.pass_tc) started
[D/utest] [ OK ] [ unit ] (test_assert_pass:16) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:17) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:19) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:20) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:22) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:23) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:25) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:26) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:28) is passed
[D/utest] [ OK ] [ unit ] (test_assert_pass:29) is passed
[I/utest] [ PASSED ] [ result ] testcase (testcases.utest.pass_tc)
[I/utest] [----------] [ testcase ] (testcases.utest.pass_tc) finished
[I/utest] [==========] [ utest ] finished
```
### 3. 提交
1. 如果是对已有测试集合的完善,需要把添加的测试用例的配置项,以及对应的依赖项添加到对应测试集合的配置文件里,如:[examples\utest\configs\kernel\mem.conf](./configs/kernel/mem.conf)。
```
CONFIG_UTEST_MEMHEAP_TC=y
# dependencies
CONFIG_RT_USING_MEMHEAP=y
```
2. 如果要添加新的测试集合,需要参考已有的测试集合,在 [examples\utest\configs](./configs) 目录下添加新的测试集合配置项。并更新 [.github\workflows\action_utest.yml](../../.github/workflows/action_utest.yml) 内的测试集合。
```
- {UTEST: "kernel/mem", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "arm", QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "kernel/mem.conf", SD_FILE: "sd.bin"}
- {UTEST: "components/utest", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "arm", QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "utest_self/self.conf", SD_FILE: "sd.bin"}
```
3. 向 RT-Thread 主仓库提交合并请求。

View File

@ -0,0 +1,4 @@
CONFIG_UTEST_CPP11_THREAD_TC=y
# dependencies
CONFIG_RT_USING_CPLUSPLUS=y
CONFIG_RT_USING_CPLUSPLUS11=y

View File

@ -0,0 +1,4 @@
CONFIG_UTEST_ATOMIC_TC=y
# dependencies
CONFIG_RT_USING_TIMER_SOFT=y
CONFIG_RT_USING_THREAD=y

View File

@ -0,0 +1,5 @@
CONFIG_UTEST_ATOMIC_TC=y
# dependencies
CONFIG_RT_USING_TIMER_SOFT=y
CONFIG_RT_USING_THREAD=y
CONFIG_RT_USING_STDC_ATOMIC=y

View File

@ -0,0 +1,4 @@
CONFIG_UTEST_DEVICE_TC=y
# dependencies
CONFIG_RT_USING_TIMER_SOFT=y
CONFIG_RT_USING_THREAD=y

View File

@ -0,0 +1,14 @@
CONFIG_UTEST_SEMAPHORE_TC=y
CONFIG_UTEST_EVENT_TC=y
CONFIG_UTEST_MESSAGEQUEUE_TC=y
CONFIG_UTEST_SIGNAL_TC=y
CONFIG_UTEST_MUTEX_TC=y
CONFIG_UTEST_MAILBOX_TC=y
CONFIG_UTEST_WORKQUEUE_TC=y
# dependencies
CONFIG_RT_USING_SEMAPHORE=y
CONFIG_RT_USING_EVENT=y
CONFIG_RT_USING_MESSAGEQUEUE=y
CONFIG_RT_USING_SIGNALS=y
CONFIG_RT_USING_MUTEX=y
CONFIG_RT_USING_MAILBOX=y

View File

@ -0,0 +1,3 @@
CONFIG_UTEST_IRQ_TC=y
CONFIG_RT_HOOK_USING_FUNC_PTR=y
# dependencies

View File

@ -0,0 +1,4 @@
CONFIG_UTEST_MEMHEAP_TC=y
# dependencies
CONFIG_RT_USING_MEMHEAP=y

View File

@ -0,0 +1,4 @@
CONFIG_UTEST_THREAD_TC=y
# dependencies
CONFIG_RT_USING_TIMER_SOFT=y
CONFIG_RT_USING_THREAD=y

View File

@ -0,0 +1,4 @@
CONFIG_UTEST_TIMER_TC=y
# dependencies
CONFIG_RT_USING_TIMER_SOFT=y

View File

@ -0,0 +1,6 @@
CONFIG_UTEST_MEMHEAP_TC=y
# dependencies
CONFIG_RT_USING_SMART=y
CONFIG_RT_USING_MEMHEAP=y
CONFIG_RT_USING_DFS_V2=y

View File

@ -0,0 +1 @@
CONFIG_UTEST_SELF_PASS_TC=y

View File

@ -0,0 +1,22 @@
menu "RT-Thread Utestcases"
config RT_USING_UTESTCASES
bool "RT-Thread Utestcases"
default n
select RT_USING_UTEST
if RT_USING_UTESTCASES
rsource "utest/Kconfig"
rsource "kernel/Kconfig"
rsource "cpp11/Kconfig"
rsource "drivers/serial_v2/Kconfig"
rsource "drivers/serial_bypass/Kconfig"
rsource "drivers/ipc/Kconfig"
rsource "posix/Kconfig"
rsource "mm/Kconfig"
rsource "tmpfs/Kconfig"
rsource "smp_call/Kconfig"
endif
endmenu

View File

@ -0,0 +1,15 @@
# RT-Thread building script for bridge
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,9 @@
menu "CPP11 Testcase"
config UTEST_CPP11_THREAD_TC
bool "Cpp11 thread test"
select RT_USING_CPLUSPLUS
select RT_USING_CPLUSPLUS11
default n
endmenu

View File

@ -0,0 +1,13 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Split('''
thread_tc.cpp
''')
CPPPATH = [cwd]
group = DefineGroup('utestcases', src, depend = ['UTEST_CPP11_THREAD_TC'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-09-03 liukang the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <thread>
static void test_thread(void)
{
int count = 0;
auto func = [&]() mutable
{
for (int i = 0; i < 100; ++i)
{
++count;
}
};
std::thread t1(func);
t1.join();
if (count != 100)
{
uassert_false(1);
}
std::thread t2(func);
t2.join();
if (count != 200)
{
uassert_false(1);
}
uassert_true(1);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_thread);
}
UTEST_TC_EXPORT(testcase, "testcases.cpp11.thread_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,15 @@
# RT-Thread building script for bridge
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,11 @@
menu "Utest IPC Testcase"
config UTEST_COMPLETION_TC
bool "rt_completion testcase"
default n
config UTEST_WORKQUEUE_TC
bool "rt_workqueue testcase"
default n
endmenu

View File

@ -0,0 +1,16 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]
if GetDepend(['UTEST_COMPLETION_TC']):
src += ['completion_tc.c', 'completion_timeout_tc.c']
if GetDepend(['UTEST_WORKQUEUE_TC']):
src += ['workqueue_tc.c']
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-04-30 Shell init ver.
*/
/**
* Test Case for rt_completion API
*
* The test simulates a producer-consumer interaction where a producer thread
* generates data, and a consumer thread consumes the data after waiting for its
* availability using rt_completion synchronization primitives.
*
* Test Criteria:
* - The producer should correctly increment the test data and signal
* completion.
* - The consumer should correctly wait for data update, consume it, and signal
* completion.
* - Data integrity should be maintained between producer and consumer.
* - Synchronization is properly done so both can see consistent data.
* - Random latency is introduced to simulate racing scenarios.
*/
#define TEST_LATENCY_TICK (1)
#define TEST_LOOP_TIMES (60 * RT_TICK_PER_SECOND)
#define TEST_PROGRESS_ON (RT_TICK_PER_SECOND)
#include "utest.h"
#include <ipc/completion.h>
#include <rtthread.h>
#include <stdlib.h>
static struct rt_completion _prod_completion;
static struct rt_completion _cons_completion;
static int _test_data = 0;
static rt_atomic_t _progress_counter;
static struct rt_semaphore _thr_exit_sem;
static void done_safely(struct rt_completion *completion)
{
rt_err_t error;
/* Signal completion */
error = rt_completion_wakeup(completion);
/* try again if failed to produce */
if (error == -RT_EEMPTY)
{
rt_thread_yield();
}
else if (error)
{
uassert_false(0);
rt_thread_delete(rt_thread_self());
}
}
static void wait_safely(struct rt_completion *completion)
{
rt_err_t error;
do
{
error = rt_completion_wait_flags(completion, RT_WAITING_FOREVER,
RT_INTERRUPTIBLE);
if (error)
{
uassert_true(error == -RT_EINTR);
rt_thread_yield();
}
else
{
break;
}
} while (1);
}
static void producer_thread_entry(void *parameter)
{
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
{
/* Produce data */
_test_data++;
/* notify consumer */
done_safely(&_prod_completion);
/* Delay before producing next data */
rt_thread_delay(TEST_LATENCY_TICK);
/* sync with consumer */
wait_safely(&_cons_completion);
}
rt_sem_release(&_thr_exit_sem);
}
static void _wait_until_edge(void)
{
rt_tick_t entry_level, current;
rt_base_t random_latency;
entry_level = rt_tick_get();
do
{
current = rt_tick_get();
} while (current == entry_level);
/* give a random latency for test */
random_latency = rand();
entry_level = current;
for (size_t i = 0; i < random_latency; i++)
{
current = rt_tick_get();
if (current != entry_level) break;
}
}
static void consumer_thread_entry(void *parameter)
{
int local_test_data = 0;
rt_thread_startup(parameter);
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
{
/* add more random case for test */
_wait_until_edge();
/* Wait for data update */
wait_safely(&_prod_completion);
/* Consume data */
if (local_test_data + 1 != _test_data)
{
LOG_I("local test data is %d, shared test data is %d",
local_test_data, _test_data);
uassert_true(0);
}
else if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
{
uassert_true(1);
}
local_test_data = _test_data;
done_safely(&_cons_completion);
}
rt_sem_release(&_thr_exit_sem);
}
static void testcase(void)
{
/* Initialize completion object */
rt_completion_init(&_prod_completion);
rt_completion_init(&_cons_completion);
/* Create producer and consumer threads */
rt_thread_t producer_thread =
rt_thread_create("producer", producer_thread_entry, RT_NULL,
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
rt_thread_t consumer_thread =
rt_thread_create("consumer", consumer_thread_entry, producer_thread,
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
uassert_true(producer_thread != RT_NULL);
uassert_true(consumer_thread != RT_NULL);
LOG_I("Summary:\n"
"\tTest times: %ds(%d)",
TEST_LOOP_TIMES / RT_TICK_PER_SECOND, TEST_LOOP_TIMES);
rt_thread_startup(consumer_thread);
for (size_t i = 0; i < 2; i++)
{
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
}
}
static rt_err_t utest_tc_init(void)
{
_test_data = 0;
_progress_counter = 0;
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_sem_detach(&_thr_exit_sem);
return RT_EOK;
}
UTEST_TC_EXPORT(testcase, "testcases.drivers.ipc.rt_completion.basic",
utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,213 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-04-30 Shell init ver.
*/
/**
* Test Case for rt_completion API
*
* The test simulates a producer-consumer interaction where a producer thread
* generates data, and a consumer thread consumes the data after waiting for its
* availability using rt_completion synchronization primitives.
*
* Test Criteria:
* - The producer produces data correctly and notifies the consumer thread.
* - The consumer receives data correctly and acknowledges receipt to the
* producer.
* - The producer and consumer threads synchronize their operations effectively.
* - Verify the correctness of data production and consumption between producer
* and consumer threads.
* - The asynchronous woken of consumer thread was handled properly so the
* consumer don't lose woken from producer.
*
* Test APIs:
* - rt_completion_init()
* - rt_completion_wakeup()
* - rt_completion_wait_flags()
*/
#define TEST_LATENCY_TICK (1)
#define TEST_LOOP_TIMES (60 * RT_TICK_PER_SECOND)
#define TEST_PROGRESS_ON (RT_TICK_PER_SECOND)
#include "utest.h"
#include <ipc/completion.h>
#include <rtthread.h>
#include <stdlib.h>
static struct rt_completion _prod_completion;
static struct rt_completion _cons_completion;
static int _test_data;
static int _async_intr_count;
static rt_atomic_t _progress_counter;
static struct rt_semaphore _thr_exit_sem;
static void _test_thread_exit_failure(char *string)
{
LOG_E("\t[TEST failed] %s", string);
rt_sem_release(&_thr_exit_sem);
rt_thread_delete(rt_thread_self());
}
static void done_safely(struct rt_completion *completion)
{
rt_err_t error;
/* Signal completion */
error = rt_completion_wakeup(completion);
/* try again if failed to produce */
if (error == -RT_EEMPTY)
{
rt_thread_yield();
}
else if (error)
{
uassert_true(error == RT_EOK);
_test_thread_exit_failure("unexpected error");
}
}
static void wait_safely(struct rt_completion *completion)
{
int try_times = 3;
rt_err_t error;
do
{
/* wait for one tick, to add more random */
error = rt_completion_wait_flags(completion, 1, RT_INTERRUPTIBLE);
if (error)
{
if (error == -RT_ETIMEOUT || error == -RT_EINTR)
{
_async_intr_count++;
}
else
{
LOG_I("Async event %d\n", error);
uassert_true(0);
}
rt_thread_yield();
}
else
{
break;
}
} while (try_times--);
if (error != RT_EOK)
{
uassert_true(error == RT_EOK);
_test_thread_exit_failure("wait failed");
}
}
static void producer_thread_entry(void *parameter)
{
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
{
/* Produce data */
_test_data++;
/* Delay before producing next data */
rt_thread_delay(TEST_LATENCY_TICK);
/* notify consumer */
done_safely(&_prod_completion);
/* sync with consumer */
wait_safely(&_cons_completion);
}
rt_sem_release(&_thr_exit_sem);
}
static void consumer_thread_entry(void *parameter)
{
int local_test_data = 0;
rt_thread_startup(parameter);
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
{
/* Wait for data update */
wait_safely(&_prod_completion);
/* Consume data */
if (local_test_data + 1 != _test_data)
{
LOG_I("local test data is %d, shared test data is %d",
local_test_data, _test_data);
uassert_true(0);
}
else if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
{
uassert_true(1);
}
local_test_data = _test_data;
done_safely(&_cons_completion);
}
rt_sem_release(&_thr_exit_sem);
}
rt_thread_t _watching_thread1;
rt_thread_t _watching_thread2;
static void testcase(void)
{
/* Initialize completion object */
rt_completion_init(&_prod_completion);
rt_completion_init(&_cons_completion);
/* Create producer and consumer threads */
rt_thread_t producer_thread =
rt_thread_create("producer", producer_thread_entry, RT_NULL,
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
rt_thread_t consumer_thread =
rt_thread_create("consumer", consumer_thread_entry, producer_thread,
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
uassert_true(producer_thread != RT_NULL);
uassert_true(consumer_thread != RT_NULL);
_watching_thread1 = consumer_thread;
_watching_thread2 = producer_thread;
rt_thread_startup(consumer_thread);
for (size_t i = 0; i < 2; i++)
{
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
}
LOG_I("Summary:\n"
"\tTest times: %ds(%d times)\n"
"\tAsync interruption count: %d\n",
TEST_LOOP_TIMES / RT_TICK_PER_SECOND, TEST_LOOP_TIMES,
_async_intr_count);
}
static rt_err_t utest_tc_init(void)
{
_test_data = 0;
_progress_counter = 0;
_async_intr_count = 0;
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_sem_detach(&_thr_exit_sem);
return RT_EOK;
}
UTEST_TC_EXPORT(testcase, "testcases.drivers.ipc.rt_completion.timeout",
utest_tc_init, utest_tc_cleanup, 1000);

View File

@ -0,0 +1,603 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-02-06 tyx first commit
* 2024-12-31 rbb666 Adding Test Cases
*/
#include "rtthread.h"
#include "rtdevice.h"
#include "utest.h"
#ifdef RT_USING_DEVICE_IPC
static rt_uint8_t get_test_thread_priority(rt_int8_t pos)
{
rt_int16_t priority;
priority = RT_SCHED_PRIV(rt_thread_self()).init_priority;
if (pos == 0)
{
return priority;
}
else
{
priority += pos;
}
if (priority < 0)
{
return 0;
}
else if (priority >= RT_THREAD_PRIORITY_MAX)
{
return RT_THREAD_PRIORITY_MAX - 1;
}
else
{
return (rt_uint8_t)priority;
}
}
static void do_work_test_fun(struct rt_work *work, void *work_data)
{
*((int *)work_data) = 1;
}
static void do_work_test(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 higher priority than the current test thread */
curr_priority = get_test_thread_priority(-1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, do_work_test_fun, (void *)&work_flag);
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
/* Delay 5 ticks to ensure that the task has been executed */
rt_thread_delay(5);
uassert_int_equal(work_flag, 1);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void do_delay_work_test_fun(struct rt_work *work, void *work_data)
{
*((rt_tick_t *)work_data) = rt_tick_get();
}
static void do_delay_work_test(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile rt_tick_t work_start = 0;
volatile rt_tick_t work_end = 0;
rt_err_t err;
/* 1 higher priority than the current test thread */
curr_priority = get_test_thread_priority(-1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, do_delay_work_test_fun, (void *)&work_end);
work_start = rt_tick_get();
/* Normal delayed work submission test */
err = rt_workqueue_submit_work(queue, &work, 10);
uassert_int_equal(err, RT_EOK);
/* Ensure that the delayed work has been executed */
rt_thread_delay(15);
/* Check if the delayed task is executed after 10 ticks */
if (work_end < work_start || work_end - work_start < 10)
{
uassert_false(1);
}
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void cancle_work_test01_fun(struct rt_work *work, void *work_data)
{
*((int *)work_data) = 1;
}
static void cancle_work_test01(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
work_flag = 0;
rt_work_init(&work, cancle_work_test01_fun, (void *)&work_flag);
/* Cancel the work before it is executed */
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
/* Cancel Now */
err = rt_workqueue_cancel_work(queue, &work);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(5);
uassert_int_equal(work_flag, 0);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void cancle_work_test02_fun(struct rt_work *work, void *work_data)
{
rt_thread_delay(10);
}
static void cancle_work_test02(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
rt_err_t err;
/* 1 higher priority than the current test thread */
curr_priority = get_test_thread_priority(-1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, cancle_work_test02_fun, RT_NULL);
/* Cancel the work while it is in progress */
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(5);
err = rt_workqueue_cancel_work(queue, &work);
uassert_int_equal(err, -RT_EBUSY);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void cancle_work_test03_fun(struct rt_work *work, void *work_data)
{
rt_thread_delay(5);
}
static void cancle_work_test03(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, cancle_work_test03_fun, RT_NULL);
/* Canceling a work after it has been executed */
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(10);
err = rt_workqueue_cancel_work(queue, &work);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void cancle_work_test04_fun(struct rt_work *work, void *work_data)
{
rt_thread_delay(10);
*((int *)work_data) = 1;
}
static void cancle_work_test04(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, cancle_work_test04_fun, (void *)&work_flag);
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(5);
/* Synchronized cancellation work */
err = rt_workqueue_cancel_work_sync(queue, &work);
uassert_int_equal(err, RT_EOK);
uassert_int_equal(work_flag, 1);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void cancle_delay_work_test01_fun(struct rt_work *work, void *work_data)
{
*((int *)work_data) = 1;
}
static void cancle_delay_work_test01(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
work_flag = 0;
rt_work_init(&work, cancle_delay_work_test01_fun, (void *)&work_flag);
err = rt_workqueue_submit_work(queue, &work, 20);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(10);
/* Cancel work */
err = rt_workqueue_cancel_work(queue, &work);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(15);
uassert_int_equal(work_flag, 0);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void repeat_work_test01_fun(struct rt_work *work, void *work_data)
{
*((int *)work_data) += 1;
}
static void repeat_work_test01(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test01", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
work_flag = 0;
rt_work_init(&work, repeat_work_test01_fun, (void *)&work_flag);
/* Multiple submissions of the same work */
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
/* The same work, before it is executed, can be submitted repeatedly and executed only once */
err = rt_workqueue_submit_work(queue, &work, 0);
if (err != RT_EOK)
{
LOG_E("L:%d err. %d", __LINE__, err);
}
rt_thread_delay(10);
/* Check if it was executed only once */
uassert_int_equal(work_flag, 1);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void repeat_work_test02_fun(struct rt_work *work, void *work_data)
{
rt_thread_delay(10);
*((int *)work_data) += 1;
}
static void repeat_work_test02(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 priority higher than current test thread */
curr_priority = get_test_thread_priority(-1);
queue = rt_workqueue_create("test02", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, repeat_work_test02_fun, (void *)&work_flag);
/* Submit work with high queue priority that will be executed immediately */
err = rt_workqueue_submit_work(queue, &work, 0);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(5);
/* Re-submission of work in progress */
err = rt_workqueue_submit_work(queue, &work, 0);
if (err != RT_EOK)
{
LOG_E("L:%d err. %d", __LINE__, err);
}
rt_thread_delay(10);
uassert_int_equal(work_flag, 1);
rt_thread_delay(10);
uassert_int_equal(work_flag, 2);
rt_workqueue_destroy(queue);
}
static struct rt_workqueue *queue_3;
static void repeat_work_test03_fun(struct rt_work *work, void *work_data)
{
int *work_flag = (int *)work_data;
(*work_flag) += 1;
rt_kprintf("work_flag:%d\n", *work_flag);
if (*work_flag < 20)
{
rt_workqueue_submit_work(queue_3, work, 0);
}
}
static void repeat_work_test03(void)
{
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 priority higher than current test thread */
curr_priority = get_test_thread_priority(-1);
queue_3 = rt_workqueue_create("test03", 2048, curr_priority);
if (queue_3 == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
rt_work_init(&work, repeat_work_test03_fun, (void *)&work_flag);
/* Submit work with high queue priority that will be executed immediately */
err = rt_workqueue_submit_work(queue_3, &work, 0);
uassert_int_equal(err, RT_EOK);
/* Wait for the work to be executed 20 times with a timeout */
err = rt_workqueue_cancel_work_sync(queue_3, &work);
uassert_int_equal(err, RT_EOK);
/* Check if the work was executed 20 times */
uassert_int_equal(work_flag, 20);
rt_workqueue_destroy(queue_3);
}
static void repeat_delay_work_test01_fun(struct rt_work *work, void *work_data)
{
*((int *)work_data) += 1;
}
static void repeat_delay_work_test01(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
work_flag = 0;
rt_work_init(&work, repeat_delay_work_test01_fun, (void *)&work_flag);
err = rt_workqueue_submit_work(queue, &work, 20);
uassert_int_equal(err, RT_EOK);
/* At this point the delayed work has not been executed */
rt_thread_delay(10);
/* Re-submission of time-delayed work */
err = rt_workqueue_submit_work(queue, &work, 20);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(15);
uassert_int_equal(work_flag, 0);
/* Waiting for delayed task execution */
rt_thread_delay(15);
uassert_int_equal(work_flag, 1);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void repeat_delay_work_test02_fun(struct rt_work *work, void *work_data)
{
rt_thread_delay(10);
*((int *)work_data) += 1;
}
static void repeat_delay_work_test02(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work;
volatile int work_flag = 0;
rt_err_t err;
/* 1 lower priority than the current test thread */
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
work_flag = 0;
rt_work_init(&work, repeat_delay_work_test02_fun, (void *)&work_flag);
err = rt_workqueue_submit_work(queue, &work, 20);
uassert_int_equal(err, RT_EOK);
/* Waiting for delayed work execution */
rt_thread_delay(25);
err = rt_workqueue_submit_work(queue, &work, 20);
uassert_int_equal(err, RT_EOK);
/* Check if the delayed work has been run only once */
rt_thread_delay(10);
uassert_int_equal(work_flag, 1);
rt_thread_delay(25);
/* Check if the delayed work is executed twice */
uassert_int_equal(work_flag, 2);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static void cancel_all_work_test_fun(struct rt_work *work, void *work_data)
{
*((int *)work_data) += 1;
}
static void cancel_all_work_test(void)
{
struct rt_workqueue *queue;
rt_uint8_t curr_priority;
struct rt_work work1;
struct rt_work work2;
struct rt_work work3;
struct rt_work work4;
volatile int work_flag = 0;
rt_err_t err;
curr_priority = get_test_thread_priority(1);
queue = rt_workqueue_create("test", 2048, curr_priority);
if (queue == RT_NULL)
{
LOG_E("queue create failed, L:%d", __LINE__);
return;
}
work_flag = 0;
rt_work_init(&work1, cancel_all_work_test_fun, (void *)&work_flag);
rt_work_init(&work2, cancel_all_work_test_fun, (void *)&work_flag);
rt_work_init(&work3, cancel_all_work_test_fun, (void *)&work_flag);
rt_work_init(&work4, cancel_all_work_test_fun, (void *)&work_flag);
err = rt_workqueue_submit_work(queue, &work1, 0);
uassert_int_equal(err, RT_EOK);
err = rt_workqueue_submit_work(queue, &work2, 0);
uassert_int_equal(err, RT_EOK);
err = rt_workqueue_submit_work(queue, &work3, 10);
uassert_int_equal(err, RT_EOK);
err = rt_workqueue_submit_work(queue, &work4, 10);
uassert_int_equal(err, RT_EOK);
err = rt_workqueue_cancel_all_work(queue);
uassert_int_equal(err, RT_EOK);
rt_thread_delay(20);
uassert_int_equal(work_flag, 0);
rt_thread_delay(100);
rt_workqueue_destroy(queue);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
/* General work queue test */
UTEST_UNIT_RUN(do_work_test);
/* Delayed work queue test */
UTEST_UNIT_RUN(do_delay_work_test);
/* Cancellation of work prior to implementation */
UTEST_UNIT_RUN(cancle_work_test01);
/* Cancellation of work during execution */
UTEST_UNIT_RUN(cancle_work_test02);
/* Cancellation of work after implementation */
UTEST_UNIT_RUN(cancle_work_test03);
/* Synchronized cancellation of work during execution */
UTEST_UNIT_RUN(cancle_work_test04);
/* Cancel delayed work before execution */
UTEST_UNIT_RUN(cancle_delay_work_test01);
/* Multiple submissions of the same work prior to implementation */
UTEST_UNIT_RUN(repeat_work_test01);
/* Multiple submissions of the same work during execution */
UTEST_UNIT_RUN(repeat_work_test02);
/* Submitting the same task multiple times in a mission */
UTEST_UNIT_RUN(repeat_work_test03);
/* Multiple submissions of the same delayed task before execution */
UTEST_UNIT_RUN(repeat_delay_work_test01);
/* Multiple submissions of the same delayed task during execution */
UTEST_UNIT_RUN(repeat_delay_work_test02);
/* Cancel all works */
UTEST_UNIT_RUN(cancel_all_work_test);
}
UTEST_TC_EXPORT(testcase, "components.drivers.ipc.workqueue_tc", utest_tc_init, utest_tc_cleanup, 300);
#endif

View File

@ -0,0 +1,7 @@
menu "Serial-Bypass Testcase"
config UTEST_SERIAL_BYPASS
bool "Serial testcase"
default n
endmenu

View File

@ -0,0 +1,11 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Glob('bypass*.c')
CPPPATH = [cwd]
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_BYPASS'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,185 @@
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-11-20 zhujiale the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
static struct rt_serial_device* _serial0;
static struct rt_spinlock lock;
static int cnt = 0;
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
#define UART_FR(base) __REG32(base + 0x18)
#define UART_DR(base) __REG32(base + 0x00)
#define UARTFR_TXFF 0x20
static rt_err_t utest_get_c(struct rt_serial_device* serial, char ch, void* data)
{
rt_atomic_add(&cnt, 1);
return RT_EOK;
}
static int utest_getc(struct rt_serial_device* serial)
{
static int num = 0;
rt_spin_lock(&lock);
if (rt_atomic_load(&num) == 10)
{
rt_atomic_flag_clear(&num);
rt_spin_unlock(&lock);
return -1;
}
rt_atomic_add(&num, 1);
rt_spin_unlock(&lock);
return 'a';
}
struct hw_uart_device
{
rt_size_t hw_base;
rt_size_t irqno;
};
static int uart_putc(struct rt_serial_device* serial, char c)
{
struct hw_uart_device* uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct hw_uart_device*)serial->parent.user_data;
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
UART_DR(uart->hw_base) = c;
return 1;
}
static const struct rt_uart_ops _utest_ops =
{
RT_NULL,
RT_NULL,
uart_putc,
utest_getc,
};
static void thread_rx1(void* parameter)
{
for (int i = 0; i < 10; i++)
{
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
}
}
static void thread_rx2(void* parameter)
{
for (int i = 0; i < 10; i++)
{
rt_workqueue_dowork(_serial0->bypass->lower_workq, &_serial0->bypass->work);
}
}
static void thread_high_priority(void* parameter)
{
for (int i = 1; i < 10; i++)
{
rt_bypass_upper_register(_serial0, "test", i, utest_get_c, RT_NULL);
rt_bypass_upper_unregister(_serial0, i);
}
}
static void thread_low_priority(void* parameter)
{
for (int i = 0; i < 20; i++)
{
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
}
}
static void bypass_rx_stress_003(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
rt_thread_t high = rt_thread_create("high_prio", thread_high_priority, RT_NULL, 2048, 15, 10);
rt_thread_t low = rt_thread_create("low_prio", thread_low_priority, RT_NULL, 2048, 20, 10);
rt_atomic_flag_clear(&cnt);
_serial0->ops = &_utest_ops;
rt_bypass_upper_register(_serial0, "test", 0, utest_get_c, RT_NULL);
rt_thread_startup(high);
rt_thread_startup(low);
rt_thread_mdelay(1000);
_serial0->ops = tmp;
rt_bypass_upper_unregister(_serial0, 0);
uassert_true(rt_atomic_load(&cnt) == 200);
}
static void bypass_rx_stress_002(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
rt_thread_t rx2 = rt_thread_create("rx2", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
rt_thread_t rx3 = rt_thread_create("rx3", thread_rx2, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
rt_atomic_flag_clear(&cnt);
_serial0->ops = &_utest_ops;
rt_bypass_lower_register(_serial0, "utest", 0, utest_get_c, RT_NULL);
rt_thread_startup(rx2);
rt_thread_startup(rx3);
rt_thread_mdelay(1000);
uassert_true(rt_atomic_load(&cnt) == 100);
_serial0->ops = tmp;
rt_bypass_lower_unregister(_serial0, 0);
}
static void bypass_rx_stress_001(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
rt_thread_t rx1 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
rt_thread_t rx2 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
cnt = 0;
_serial0->ops = &_utest_ops;
rt_bypass_upper_register(_serial0, "utest", 0, utest_get_c, RT_NULL);
rt_thread_startup(rx1);
rt_thread_startup(rx2);
rt_thread_mdelay(1000);
uassert_true(rt_atomic_load(&cnt) == 200);
_serial0->ops = tmp;
rt_bypass_upper_unregister(_serial0, 0);
}
static rt_err_t utest_tc_init(void)
{
_serial0 = (struct rt_serial_device*)rt_console_get_device();
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void _testcase(void)
{
UTEST_UNIT_RUN(bypass_rx_stress_001);
UTEST_UNIT_RUN(bypass_rx_stress_002);
UTEST_UNIT_RUN(bypass_rx_stress_003);
}
UTEST_TC_EXPORT(_testcase, "testcase.bypass.conflict.001", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-11-20 zhujiale the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
static struct rt_serial_device* _serial0;
static int cnt = 0;
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
#define UART_FR(base) __REG32(base + 0x18)
#define UART_DR(base) __REG32(base + 0x00)
#define UARTFR_TXFF 0x20
struct hw_uart_device
{
rt_size_t hw_base;
rt_size_t irqno;
};
static int uart_putc(struct rt_serial_device* serial, char c)
{
struct hw_uart_device* uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct hw_uart_device*)serial->parent.user_data;
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
UART_DR(uart->hw_base) = c;
return 1;
}
static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data)
{
static rt_uint8_t num = 0;
num++;
uassert_true(ch == ('a' + num));
return RT_EOK;
}
static int utest_getc_2(struct rt_serial_device* serial)
{
static rt_uint8_t num = 0;
if (num == 20)
return -1;
num++;
return 'a' + num;
}
static const struct rt_uart_ops _utest_ops2 =
{
RT_NULL,
RT_NULL,
uart_putc,
utest_getc_2,
};
static rt_err_t utest_lower_run(struct rt_serial_device* serial, char ch, void* data)
{
uassert_true(ch == 'a');
cnt++;
return RT_EOK;
}
static int utest_getc(struct rt_serial_device* serial)
{
static rt_uint8_t num = 0;
if (num == 10)
return -1;
num++;
return 'a';
}
static const struct rt_uart_ops _utest_ops =
{
RT_NULL,
RT_NULL,
uart_putc,
utest_getc,
};
static void bypass_lower_001(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
_serial0->ops = &_utest_ops;
rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run, RT_NULL);
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
rt_thread_mdelay(100);
uassert_true(cnt == 10);
_serial0->ops = tmp;
rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
}
static void bypass_lower_002(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
_serial0->ops = &_utest_ops2;
rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL);
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
rt_thread_mdelay(100);
uassert_true(cnt == 10);
_serial0->ops = tmp;
rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
}
static rt_err_t utest_tc_init(void)
{
_serial0 = (struct rt_serial_device*)rt_console_get_device();
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void _testcase(void)
{
UTEST_UNIT_RUN(bypass_lower_001);
UTEST_UNIT_RUN(bypass_lower_002);
}
UTEST_TC_EXPORT(_testcase, "testcase.bypass.lower.001", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-11-20 zhujiale the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
static struct rt_serial_device* _serial0;
static struct rt_spinlock lock;
static rt_err_t utest_001_run(struct rt_serial_device* serial, char ch, void* data)
{
return 0;
}
static void thread_serial_register1(void* parameter)
{
for (int i = 2; i < 10; i += 2)
{
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
}
}
static void thread_serial_register_upper(void* parameter)
{
for (int i = 1; i < 10; i++)
{
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
}
}
static void thread_serial_register_lower(void* parameter)
{
for (int i = 1; i < 10; i++)
{
rt_bypass_lower_register(_serial0, "test", i, utest_001_run, RT_NULL);
}
}
static void bypass_register_001(void)
{
rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL);
rt_thread_startup(t1);
for (int i = 1; i < 10; i += 2)
{
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
}
rt_thread_mdelay(1000);
rt_list_t* node = _serial0->bypass->upper_h->head.next;
for (int i = 0; i < 10;i++)
{
rt_list_t* next = node->next;
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
uassert_true(temp->level == i);
rt_bypass_upper_unregister(_serial0, temp->level);
node = next;
}
}
static void bypass_register_002(void)
{
rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register_upper, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
rt_thread_t t2 = rt_thread_create("serial_register", thread_serial_register_lower, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL);
rt_thread_startup(t1);
rt_thread_startup(t2);
rt_thread_mdelay(1000);
rt_list_t* node = _serial0->bypass->upper_h->head.next;
for (int i = 0; i < 10;i++)
{
rt_list_t* next = node->next;
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
uassert_true(temp->level == i);
rt_bypass_upper_unregister(_serial0, temp->level);
node = next;
}
node = _serial0->bypass->lower_h->head.next;
for (int i = 1; i < 10;i++)
{
rt_list_t* next = node->next;
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
uassert_true(temp->level == i);
rt_bypass_lower_unregister(_serial0, temp->level);
node = next;
}
}
static rt_err_t utest_tc_init(void)
{
_serial0 = (struct rt_serial_device*)rt_console_get_device();
rt_spin_lock_init(&lock);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void _testcase(void)
{
UTEST_UNIT_RUN(bypass_register_001);
UTEST_UNIT_RUN(bypass_register_002);
}
UTEST_TC_EXPORT(_testcase, "testcase.bypass.register.001", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-11-20 zhujiale the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
static struct rt_serial_device* _serial0;
static int cnt;
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
#define UART_FR(base) __REG32(base + 0x18)
#define UART_DR(base) __REG32(base + 0x00)
#define UARTFR_TXFF 0x20
static rt_err_t utest_upper_run(struct rt_serial_device* serial, char ch, void* data)
{
uassert_true(ch == 'a');
cnt++;
return RT_EOK;
}
static int utest_getc(struct rt_serial_device* serial)
{
static rt_uint8_t num = 0;
if (num == 10)
return -1;
num++;
return 'a';
}
struct hw_uart_device
{
rt_size_t hw_base;
rt_size_t irqno;
};
static int uart_putc(struct rt_serial_device* serial, char c)
{
struct hw_uart_device* uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct hw_uart_device*)serial->parent.user_data;
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
UART_DR(uart->hw_base) = c;
return 1;
}
static const struct rt_uart_ops _utest_ops =
{
RT_NULL,
RT_NULL,
uart_putc,
utest_getc,
};
static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data)
{
static rt_uint8_t num = 0;
num++;
uassert_true(ch == ('a' + num));
return RT_EOK;
}
static int utest_getc_2(struct rt_serial_device* serial)
{
static rt_uint8_t num = 0;
if (num == 20)
return -1;
num++;
return 'a' + num;
}
static const struct rt_uart_ops _utest_ops2 =
{
RT_NULL,
RT_NULL,
uart_putc,
utest_getc_2,
};
static void bypass_upper_001(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
_serial0->ops = &_utest_ops;
rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_LEVEL_1, utest_upper_run, RT_NULL);
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
uassert_true(cnt == 10);
_serial0->ops = tmp;
rt_bypass_upper_unregister(_serial0, RT_BYPASS_LEVEL_1);
}
static void bypass_upper_002(void)
{
const struct rt_uart_ops* tmp = _serial0->ops;
_serial0->ops = &_utest_ops2;
rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL);
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
rt_thread_mdelay(100);
uassert_true(cnt == 10);
_serial0->ops = tmp;
rt_bypass_upper_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
}
static rt_err_t utest_tc_init(void)
{
_serial0 = (struct rt_serial_device*)rt_console_get_device();
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void _testcase(void)
{
UTEST_UNIT_RUN(bypass_upper_001);
UTEST_UNIT_RUN(bypass_upper_002);
}
UTEST_TC_EXPORT(_testcase, "testcase.bypass.upper.001", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,7 @@
menu "Utest Serial Testcase"
config UTEST_SERIAL_TC
bool "Serial testcase"
default n
endmenu

View File

@ -0,0 +1,158 @@
## 1、介绍
该目录下 c 文件是新版本串口的测试用例,在 `examples/utest/testcases/drivers/serial_v2` 目录结构里,该测试用例用来测试串口的各个操作模式是否正常工作。
## 2、 文件说明
| 文件 | 描述 |
| ---------------- | ----------------------------------------- |
| uart_rxb_txb.c | 串口接收阻塞和发送阻塞模式 的测试用例 |
| uart_rxb_txnb.c | 串口接收阻塞和发送非阻塞模式 的测试用例 |
| uart_rxnb_txb.c | 串口接收非阻塞和发送阻塞模式 的测试用例 |
| uart_rxnb_txnb.c | 串口接收非阻塞和发送非阻塞模式 的测试用例 |
| uart_blocking_tx.c| 串口阻塞发送模式 的测试 |
| uart_blocking_rx.c| 串口阻塞接收模式 的测试 |
| uart_nonblocking_tx.c| 串口非阻塞发送模式 的测试 |
| uart_nonblocking_rx.c | 串口非阻塞接收模式 的测试 |
## 3、软硬件环境
硬件上需要支持 RT-Thread 的完整版操作系统版本为4.0.4及以上,且硬件有串口硬件外设,软件上需要支持 内核接口、IPC 、Device 框架。
## 4、测试项
### 4.1 测试说明
上文所提及的模式是指串口使用时的操作模式不涉及硬件的工作模式的配置情况硬件工作模式一般有轮询POLL、中断INT、DMA因此使用时需要结合具体的硬件工作模式去配置使用。例如 发送阻塞和接收非阻塞模式 这个测试有很多种硬件配置配置情况例如DMA发送阻塞和DMA接收非阻塞INT发送阻塞和DMA接收非阻塞POLL发送阻塞和DMA接收非阻塞等等。因此通过排列组合后的测试场景有4*9=36种有意义的组合方式为20种。如下表
| 接收非阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 |
| ---------- | -------- | ----------------- | ---------------- |
| POLL | POLL | RX_POLL + TX_POLL | |
| | INT | RX_POLL + TX_INT | |
| | DMA | RX_POLL + TX_DMA | |
| INT | POLL | RX_INT + TX_POLL | ✔ |
| | INT | RX_INT + TX_INT | ✔ |
| | DMA | RX_INT + TX_DMA | ✔ |
| DMA | POLL | RX_DMA + TX_POLL | ✔ |
| | INT | RX_DMA + TX_INT | ✔ |
| | DMA | RX_DMA + TX_DMA | ✔ |
| 接收非阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 |
| ---------- | ---------- | ----------------- | ---------------- |
| POLL | POLL | RX_POLL + TX_POLL | |
| | INT | RX_POLL + TX_INT | |
| | DMA | RX_POLL + TX_DMA | |
| INT | POLL | RX_INT + TX_POLL | |
| | INT | RX_INT + TX_INT | ✔ |
| | DMA | RX_INT + TX_DMA | ✔ |
| DMA | POLL | RX_DMA + TX_POLL | |
| | INT | RX_DMA + TX_INT | ✔ |
| | DMA | RX_DMA + TX_DMA | ✔ |
| 接收阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 |
| -------- | -------- | ----------------- | ---------------- |
| POLL | POLL | RX_POLL + TX_POLL | |
| | INT | RX_POLL + TX_INT | |
| | DMA | RX_POLL + TX_DMA | |
| INT | POLL | RX_INT + TX_POLL | ✔ |
| | INT | RX_INT + TX_INT | ✔ |
| | DMA | RX_INT + TX_DMA | ✔ |
| DMA | POLL | RX_DMA + TX_POLL | ✔ |
| | INT | RX_DMA + TX_INT | ✔ |
| | DMA | RX_DMA + TX_DMA | ✔ |
| 接收阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 |
| -------- | ---------- | ----------------- | ---------------- |
| POLL | POLL | RX_POLL + TX_POLL | |
| | INT | RX_POLL + TX_INT | |
| | DMA | RX_POLL + TX_DMA | |
| INT | POLL | RX_INT + TX_POLL | |
| | INT | RX_INT + TX_INT | ✔ |
| | DMA | RX_INT + TX_DMA | ✔ |
| DMA | POLL | RX_DMA + TX_POLL | |
| | INT | RX_DMA + TX_INT | ✔ |
| | DMA | RX_DMA + TX_DMA | ✔ |
需要解释的是为什么会存在无意义的组合模式举个例子非阻塞模式下肯定是不会出现POLL轮询方式的因为POLL方式已经表明是阻塞方式了。
该测试用例在测试多种组合时,需要通过更改`rtconfig.h`文件对硬件模式进行静态配置。
### 4.2 测试思路
前四个测试用例的测试思路:
>硬件上:**短接串口的发送TX引脚和接收RX引脚完成自发自收的回路**。
>
>软件上创建两个线程A和BA为接收线程B为发送线程设置A线程优先级比B线程优先级高。发送线程发送随机长度长度范围是 0 到 1000的数据接收线程接收到数据进行校验数据正确则测试通过默认测试100次。
后四个测试用例的测试思路:
>硬件上: **不需要将TX,RX引脚进行短接**,每次只针对发送或接收中的一种进行测试,更为简单与直接
>
>软件上: 四个样例每次仅测试TX/RX中的一种引脚与一种对应的阻塞/非阻塞模式
>四种测试模式具体分为:
>>阻塞接收模式----(硬件工作模式可选: 轮询, 中断, DMA)
>>阻塞发送模式----(硬件工作模式可选: 轮询, 中断, DMA)
>>非阻塞接收模式--(硬件工作模式可选: 中断, DMA)
>>非阻塞发送模式--(硬件工作模式可选: 中断, DMA)
>
>其中阻塞或非阻塞背后的具体硬件工作模式选择(如 轮询, 中断, DMA)需要对`rtconfig.h`文件做出配置,具体配置流程可见文章中关于
[seril_v2硬件工作模式的选择](https://club.rt-thread.org/ask/article/b4c536303c8e2335.html "serial_v2源码分析")一节.
>
>发送测试流程 :
>>1. 先关闭串口,再以需要测试的模式打开.
>>2. 然后依次发送 UART_SEND_TIMES(默认为400) * 1024, 8, 32, 128, 512, 1024个数据.
>>3. 发送的同时记录每次发送所耗费的时钟周期与成功发送的数据数量.
>>3. 打印记录的数据,通过时钟周期来反应发送效率, 通过成功发送的数据量来反应是否产生丢包问题.
>
>接收测试流程 :
>>1. 先关闭串口,再以需要测试的模式打开.
>>2. 然后以此接收 256, 256, 256, 128, 128, 共计1024个数据
>>3. 接收的同时记录成功接收的数据数量
>>4. 打印记录的数据, 通过现实成功接收的数据量与串口发送的数据量做对比,来验证是否出现丢包问题
## 5、配置
使用该测试用例需要在 `env` 工具的 `menuconfig` 中做相关配置,配置如下所示(使用 RT-Thread-Studio 的配置路径一致
```
RT-Thread Utestcases --->
[*] RT-Thread Utestcases --->
Utest Serial Testcase --->
[*] Serial testcase
```
## 6、使用
\- 编译下载。
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_blocking_tx` 运行串口阻塞发送测试
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_blocking_rx` 运行串口阻塞接收测试
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_nonblocking_tx` 运行串口非阻塞发送测试
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_nonblocking_rx` 运行串口非阻塞接收测试
如果仅仅配置了 `Serial testcase` 相关的测试用例,则直接输入 `utest_run` 运行即可将上述测试用例按序测试。
## 7、注意事项
\- 需配置正确的测试用例。
\- 如有需要,可开启 ULOG 查看测试用例日志信息。
\- 需在 MSH 中输入正确的命令行。
\- 测试用例默认的测试数据长度范围最大为1000字节如果接收端的缓冲区大小配置为小于1000字节时那么在测试接收阻塞模式时将会由于获取不了1000字节长度导致线程持续阻塞因为测试用例是按 `recv_len` 长度去接收的,而不是按照单字节去接收的),因此建议接收端的缓冲区大小 (对应宏例如为 `BSP_UART2_RX_BUFSIZE`设置为1024即可当然也可按需减小测试的最大数据长度。
\- 该测试用例需要结合硬件具体的工作模式POLL 、INT、DMA进行测试而硬件工作模式只能选择一种因此需要在 `rtconfig.h` 中对串口相应的宏进行配置,来选择不同的工作模式去进行测试。

View File

@ -0,0 +1,20 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Split('''
uart_rxb_txnb.c
uart_rxb_txb.c
uart_rxnb_txb.c
uart_rxnb_txnb.c
uart_blocking_rx.c
uart_blocking_tx.c
uart_nonblocking_rx.c
uart_nonblocking_tx.c
''')
CPPPATH = [cwd]
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_TC'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,93 @@
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
#define SERIAL_UART_NAME "uart2"
#ifdef UTEST_SERIAL_TC
static rt_bool_t block_read(rt_device_t uart_dev)
{
rt_size_t total_length, recv_length;
rt_uint8_t uart_read_buffer[1024], log_buffer[64];
/* make sure device is closed and reopen it */
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_RX_BLOCKING);
rt_sprintf(log_buffer, "\nBLOCKING READ BEGIN, PLEASE SEND SOME DATAS\n");
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
total_length = 0;
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
total_length += recv_length;
rt_sprintf(log_buffer, "\nblock : %d bytes read, total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
total_length += recv_length;
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
total_length += recv_length;
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
total_length += recv_length;
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
total_length += recv_length;
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
rt_thread_mdelay(1000);
rt_sprintf(log_buffer, "BLOCKING READ END");
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
return RT_TRUE;
}
static void uart_test_blocking_rx(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
uassert_not_null(uart_dev);
uassert_true (block_read(uart_dev));
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(uart_test_blocking_rx);
}
UTEST_TC_EXPORT(testcase, "uart_blocking_rx", utest_tc_init, utest_tc_cleanup, 10);
#endif

View File

@ -0,0 +1,118 @@
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
#define SERIAL_UART_NAME "uart2"
#define UART_SEND_TIMES 400
#define UART_TEST_NUMBER 6
#ifdef UTEST_SERIAL_TC
static rt_bool_t block_write(rt_device_t uart_dev)
{
rt_size_t i, wr_sz, index, write_num_array[UART_TEST_NUMBER], total_write_num[UART_TEST_NUMBER];
rt_tick_t tick1, tick2, tick_array[UART_TEST_NUMBER];
rt_uint8_t uart_write_buffer[1024];
for (i = 0; i < 1024; i++)
uart_write_buffer[i] = '0' + (i % 49);
/* make sure device is closed and reopen it */
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING);
LOG_D("\nBLOCKING WRITE BEGIN\n");
rt_thread_mdelay(2000);
index = 0;
wr_sz = 0;
tick1 = rt_tick_get();
for(i = 0; i < UART_SEND_TIMES; i++)
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 1024);
tick2 = rt_tick_get();
total_write_num[index] = UART_SEND_TIMES * 1024;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 8);
tick2 = rt_tick_get();
total_write_num[index] = 8;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 32);
tick2 = rt_tick_get();
total_write_num[index] = 32;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 128);
tick2 = rt_tick_get();
total_write_num[index] = 128;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 512);
tick2 = rt_tick_get();
total_write_num[index] = 512;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 1024);
tick2 = rt_tick_get();
total_write_num[index] = 1024;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
rt_thread_mdelay(1000);
LOG_D("\nBLOCKING_TX END\n");
for(i = 0; i < index; i++)
{
LOG_D("\nBLOCKING_MODE : write %d / %d bytes in %d ticks\n", write_num_array[i], total_write_num[i], tick_array[i]);
rt_thread_mdelay(1000);
}
return RT_TRUE;
}
static void uart_test_blocking_tx(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
uassert_not_null(uart_dev);
uassert_true (block_write(uart_dev));
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(uart_test_blocking_tx);
}
UTEST_TC_EXPORT(testcase, "uart_blocking_tx", utest_tc_init, utest_tc_cleanup, 10);
#endif

View File

@ -0,0 +1,107 @@
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
#define SERIAL_UART_NAME "uart2"
#ifdef UTEST_SERIAL_TC
static rt_bool_t nonblock_read(rt_device_t uart_dev)
{
rt_size_t total_length, recv_length;
rt_uint8_t uart_read_buffer[1024], log_buffer[64];
/* make sure device is closed and reopen it */
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING);
rt_sprintf(log_buffer, "\nNONBLOCKING READ BEGIN, PLEASE SEND SOME DATAS\n");
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
total_length = 0;
rt_device_write(uart_dev, 0, "5\n", 2);
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
total_length += recv_length;
rt_thread_mdelay(1000);
rt_sprintf(log_buffer, "\nnonblock : %d bytes read, total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
rt_device_write(uart_dev, 0, "4\n", 2);
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
total_length += recv_length;
rt_thread_mdelay(1000);
rt_sprintf(log_buffer,"\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev,0,log_buffer, rt_strlen(log_buffer));
rt_device_write(uart_dev, 0, "3\n", 2);
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
total_length += recv_length;
rt_thread_mdelay(1000);
rt_sprintf(log_buffer, "\nnonblock : %d bytes read, total: %d \n", recv_length, total_length);
rt_device_write(uart_dev,0,log_buffer, rt_strlen(log_buffer));
rt_device_write(uart_dev, 0, "2\n", 2);
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
rt_device_write(uart_dev, 0, uart_read_buffer, 128);
total_length += recv_length;
rt_thread_mdelay(1000);
rt_sprintf(log_buffer,"\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
rt_device_write(uart_dev, 0, "1\n", 2);
recv_length = 0;
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
rt_device_write(uart_dev, 0, uart_read_buffer, 128);
total_length += recv_length;
rt_thread_mdelay(1000);
rt_sprintf(log_buffer, "\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
rt_sprintf(log_buffer, "BLOCKING READ END");
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
return RT_TRUE;
}
static void uart_test_nonblocking_rx(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
uassert_not_null(uart_dev);
uassert_true (nonblock_read(uart_dev));
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(uart_test_nonblocking_rx);
}
UTEST_TC_EXPORT(testcase, "uart_nonblocking_rx", utest_tc_init, utest_tc_cleanup, 10);
#endif

View File

@ -0,0 +1,128 @@
#include <rtthread.h>
#include <rtdevice.h>
#include "utest.h"
#define SERIAL_UART_NAME "uart2"
#define UART_SEND_TIMES 400
#define UART_TEST_NUMBER 6
#ifdef UTEST_SERIAL_TC
static rt_bool_t nonblock_write(rt_device_t uart_dev)
{
rt_size_t wr_sz = 0, tmp = 0, i, write_num_array[UART_TEST_NUMBER], total_write_num[UART_TEST_NUMBER], index;
rt_tick_t tick1, tick2, tick_array[UART_TEST_NUMBER];
rt_uint8_t uart_write_buffer[1024];
for (i = 0; i < 1024; i++)
uart_write_buffer[i] = '0' + (i % 50);
/* make sure device is closed and reopen it */
while(rt_device_close(uart_dev) != -RT_ERROR);
uart_dev = rt_device_find(SERIAL_UART_NAME);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_NON_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING);
LOG_D("\nNONBLOCKING WRITE BEGIN\n");
rt_thread_mdelay(2000);
index = 0;
tmp = 0;
tick1 = rt_tick_get();
for (i = 0; i < UART_SEND_TIMES; i++)
{
wr_sz = 0;
while(wr_sz < 1024)
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 1024-wr_sz);
tmp += wr_sz;
}
tick2 = rt_tick_get();
total_write_num[index] = UART_SEND_TIMES * 1024;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = tmp;
wr_sz = 0;
tick1 = rt_tick_get();
while(wr_sz < 8)
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 8-wr_sz);
tick2 = rt_tick_get();
total_write_num[index] = 8;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
while(wr_sz < 32)
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 32-wr_sz);
tick2 = rt_tick_get();
total_write_num[index] = 32;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
while(wr_sz < 128)
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 128-wr_sz);
tick2 = rt_tick_get();
total_write_num[index] = 128;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
while(wr_sz < 512)
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 512-wr_sz);
tick2 = rt_tick_get();
total_write_num[index] = 512;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
wr_sz = 0;
tick1 = rt_tick_get();
while(wr_sz < 1024)
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 1024-wr_sz);
tick2 = rt_tick_get();
total_write_num[index] = 1024;
tick_array[index] = tick2 - tick1;
write_num_array[index++] = wr_sz;
rt_thread_mdelay(1000);
LOG_D("\nNONBLOCKING_TX END\n");
for(i = 0; i < index; i++)
{
LOG_D("\nNONBLOCKING_MODE : write %d / %d bytes in %d ticks\n", write_num_array[i], total_write_num[i], tick_array[i]);
rt_thread_mdelay(1000);
}
return RT_TRUE;
}
static void uart_test_nonblocking_tx(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
uassert_not_null(uart_dev);
uassert_true (nonblock_write(uart_dev));
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_device_t uart_dev;
uart_dev = rt_device_find(SERIAL_UART_NAME);
while(rt_device_close(uart_dev) != -RT_ERROR);
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(uart_test_nonblocking_tx);
}
UTEST_TC_EXPORT(testcase, "uart_nonblocking_tx", utest_tc_init, utest_tc_cleanup, 10);
#endif

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-16 KyleChan the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <rtdevice.h>
#include <stdlib.h>
#define TC_UART_DEVICE_NAME "uart2"
#define TC_UART_SEND_TIMES 100
#ifdef UTEST_SERIAL_TC
#define TEST_UART_NAME TC_UART_DEVICE_NAME
static struct rt_serial_device *serial;
static rt_uint8_t uart_over_flag;
static rt_bool_t uart_result = RT_TRUE;
static rt_err_t uart_find(void)
{
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
if (serial == RT_NULL)
{
LOG_E("find %s device failed!\n", TEST_UART_NAME);
return -RT_ERROR;
}
return RT_EOK;
}
static void uart_send_entry(void *parameter)
{
rt_uint8_t *uart_write_buffer;
rt_uint16_t send_len;
rt_uint32_t i = 0;
send_len = *(rt_uint16_t *)parameter;
/* assign send buffer */
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
if (uart_write_buffer == RT_NULL)
{
LOG_E("Without spare memory for uart dma!");
uart_result = RT_FALSE;
return;
}
rt_memset(uart_write_buffer, 0, send_len);
for (i = 0; i < send_len; i++)
{
uart_write_buffer[i] = (rt_uint8_t)i;
}
/* send buffer */
if (rt_device_write(&serial->parent, 0, uart_write_buffer, send_len) != send_len)
{
LOG_E("device write failed\r\n");
}
rt_free(uart_write_buffer);
}
static void uart_rec_entry(void *parameter)
{
rt_uint16_t rev_len;
rev_len = *(rt_uint16_t *)parameter;
rt_uint8_t *ch;
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
rt_int32_t cnt, i;
rt_uint8_t last_old_data;
rt_bool_t fisrt_flag = RT_TRUE;
rt_uint32_t all_receive_length = 0;
while (1)
{
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
if (cnt == 0)
{
continue;
}
if (fisrt_flag != RT_TRUE)
{
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
{
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
else
{
fisrt_flag = RT_FALSE;
}
for (i = 0; i < cnt - 1; i++)
{
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
{
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
all_receive_length += cnt;
if (all_receive_length >= rev_len)
break;
else
last_old_data = ch[cnt - 1];
}
rt_free(ch);
uart_over_flag = RT_TRUE;
}
static rt_err_t uart_api(rt_uint16_t length)
{
rt_thread_t thread_send = RT_NULL;
rt_thread_t thread_recv = RT_NULL;
rt_err_t result = RT_EOK;
uart_over_flag = RT_FALSE;
result = uart_find();
if (result != RT_EOK)
{
return -RT_ERROR;
}
/* Reinitialize */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
config.baud_rate = BAUD_RATE_115200;
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
if (result != RT_EOK)
{
LOG_E("Open uart device failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
thread_send = rt_thread_create("uart_send", uart_send_entry, &length, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &length, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
if ((thread_send != RT_NULL) && (thread_recv != RT_NULL))
{
rt_thread_startup(thread_send);
rt_thread_startup(thread_recv);
}
else
{
result = -RT_ERROR;
goto __exit;
}
while (1)
{
if (uart_result != RT_TRUE)
{
LOG_E("The test for uart dma is failure.");
result = -RT_ERROR;
goto __exit;
}
if (uart_over_flag == RT_TRUE)
{
goto __exit;
}
/* waiting for test over */
rt_thread_mdelay(5);
}
__exit:
rt_device_close(&serial->parent);
return result;
}
static void tc_uart_api(void)
{
rt_uint32_t times = 0;
rt_uint16_t num = 0;
while (TC_UART_SEND_TIMES - times)
{
num = (rand() % 1000) + 1;
if(uart_api(num) == RT_EOK)
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
else
{
LOG_E("uart test error");
break;
}
}
uassert_true(uart_over_flag == RT_TRUE);
}
static rt_err_t utest_tc_init(void)
{
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
uart_result = RT_TRUE;
uart_over_flag = RT_FALSE;
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(tc_uart_api);
}
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxb_txb", utest_tc_init, utest_tc_cleanup, 30);
#endif /* TC_UART_USING_TC */

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-16 KyleChan the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <rtdevice.h>
#include <stdlib.h>
#define TC_UART_DEVICE_NAME "uart2"
#define TC_UART_SEND_TIMES 100
#ifdef UTEST_SERIAL_TC
#define TEST_UART_NAME TC_UART_DEVICE_NAME
static struct rt_serial_device *serial;
static rt_sem_t tx_sem;
static rt_uint8_t uart_over_flag;
static rt_bool_t uart_result = RT_TRUE;
static rt_err_t uart_find(void)
{
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
if (serial == RT_NULL)
{
LOG_E("find %s device failed!\n", TEST_UART_NAME);
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t uart_tx_completion(rt_device_t device, void *buffer)
{
rt_sem_release(tx_sem);
return RT_EOK;
}
static void uart_send_entry(void *parameter)
{
rt_uint8_t *uart_write_buffer;
rt_uint16_t send_len, len = 0;
rt_err_t result;
rt_uint32_t i = 0;
send_len = *(rt_uint16_t *)parameter;
/* assign send buffer */
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
if (uart_write_buffer == RT_NULL)
{
LOG_E("Without spare memory for uart dma!");
uart_result = RT_FALSE;
return;
}
rt_memset(uart_write_buffer, 0, send_len);
for (i = 0; i < send_len; i++)
{
uart_write_buffer[i] = (rt_uint8_t)i;
}
/* send buffer */
while (send_len - len)
{
len += rt_device_write(&serial->parent, 0, uart_write_buffer + len, send_len - len);
result = rt_sem_take(tx_sem, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
LOG_E("take sem err in send.");
}
}
rt_free(uart_write_buffer);
}
static void uart_rec_entry(void *parameter)
{
rt_uint16_t rev_len;
rev_len = *(rt_uint16_t *)parameter;
rt_uint8_t *ch;
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
rt_int32_t cnt, i;
rt_uint8_t last_old_data;
rt_bool_t fisrt_flag = RT_TRUE;
rt_uint32_t all_receive_length = 0;
while (1)
{
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
if (cnt != rev_len)
{
continue;
}
if (fisrt_flag != RT_TRUE)
{
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
{
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
else
{
fisrt_flag = RT_FALSE;
}
for (i = 0; i < cnt - 1; i++)
{
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
{
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
all_receive_length += cnt;
if (all_receive_length >= rev_len)
break;
else
last_old_data = ch[cnt - 1];
}
rt_free(ch);
uart_over_flag = RT_TRUE;
}
static rt_err_t uart_api(rt_uint16_t test_buf)
{
rt_thread_t thread_send = RT_NULL;
rt_thread_t thread_recv = RT_NULL;
rt_err_t result = RT_EOK;
uart_over_flag = RT_FALSE;
result = uart_find();
if (result != RT_EOK)
{
return -RT_ERROR;
}
tx_sem = rt_sem_create("tx_sem", 0, RT_IPC_FLAG_PRIO);
if (tx_sem == RT_NULL)
{
LOG_E("Init sem failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
/* Reinitialize */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
config.baud_rate = BAUD_RATE_115200;
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING);
if (result != RT_EOK)
{
LOG_E("Open uart device failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
/* set receive callback function */
result = rt_device_set_tx_complete(&serial->parent, uart_tx_completion);
if (result != RT_EOK)
{
goto __exit;
}
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
if (thread_send != RT_NULL && thread_recv != RT_NULL)
{
rt_thread_startup(thread_recv);
rt_thread_startup(thread_send);
}
else
{
result = -RT_ERROR;
goto __exit;
}
while (1)
{
if (uart_result != RT_TRUE)
{
LOG_E("The test for uart dma is failure.");
result = -RT_ERROR;
goto __exit;
}
if (uart_over_flag == RT_TRUE)
{
goto __exit;
}
/* waiting for test over */
rt_thread_mdelay(5);
}
__exit:
if (tx_sem)
rt_sem_delete(tx_sem);
rt_device_close(&serial->parent);
return result;
}
static void tc_uart_api(void)
{
rt_uint32_t times = 0;
rt_uint16_t num = 0;
while (TC_UART_SEND_TIMES - times)
{
num = (rand() % 1000) + 1;
if(uart_api(num) == RT_EOK)
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
else
{
LOG_E("uart test error");
break;
}
}
uassert_true(uart_over_flag == RT_TRUE);
}
static rt_err_t utest_tc_init(void)
{
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
tx_sem = RT_NULL;
uart_result = RT_TRUE;
uart_over_flag = RT_FALSE;
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(tc_uart_api);
}
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxb_txnb", utest_tc_init, utest_tc_cleanup, 30);
#endif

View File

@ -0,0 +1,266 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-16 KyleChan the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <rtdevice.h>
#include <stdlib.h>
#define TC_UART_DEVICE_NAME "uart2"
#define TC_UART_SEND_TIMES 100
#ifdef UTEST_SERIAL_TC
#define TEST_UART_NAME TC_UART_DEVICE_NAME
static struct rt_serial_device *serial;
static rt_sem_t rx_sem;
static rt_uint8_t uart_over_flag;
static rt_bool_t uart_result = RT_TRUE;
static rt_err_t uart_find(void)
{
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
if (serial == RT_NULL)
{
LOG_E("find %s device failed!\n", TEST_UART_NAME);
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t uart_rx_indicate(rt_device_t device, rt_size_t size)
{
rt_sem_release(rx_sem);
return RT_EOK;
}
static void uart_send_entry(void *parameter)
{
rt_uint8_t *uart_write_buffer;
rt_uint16_t send_len;
rt_uint32_t i = 0;
send_len = *(rt_uint16_t *)parameter;
/* assign send buffer */
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
if (uart_write_buffer == RT_NULL)
{
LOG_E("Without spare memory for uart dma!");
uart_result = RT_FALSE;
return;
}
rt_memset(uart_write_buffer, 0, send_len);
for (i = 0; i < send_len; i++)
{
uart_write_buffer[i] = (rt_uint8_t)i;
}
/* send buffer */
if (rt_device_write(&serial->parent, 0, uart_write_buffer, send_len) != send_len)
{
LOG_E("device write failed\r\n");
}
rt_free(uart_write_buffer);
}
static void uart_rec_entry(void *parameter)
{
rt_uint16_t rev_len;
rev_len = *(rt_uint16_t *)parameter;
rt_uint8_t *ch;
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
rt_int32_t cnt, i;
rt_uint8_t last_old_data;
rt_bool_t fisrt_flag = RT_TRUE;
rt_uint32_t all_receive_length = 0;
while (1)
{
rt_err_t result;
result = rt_sem_take(rx_sem, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
LOG_E("take sem err in recv.");
}
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
if (cnt == 0)
{
continue;
}
if (fisrt_flag != RT_TRUE)
{
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
{
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
else
{
fisrt_flag = RT_FALSE;
}
for (i = 0; i < cnt - 1; i++)
{
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
{
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
all_receive_length += cnt;
if (all_receive_length >= rev_len)
break;
else
last_old_data = ch[cnt - 1];
}
rt_free(ch);
uart_over_flag = RT_TRUE;
}
static rt_err_t uart_api(rt_uint16_t test_buf)
{
rt_thread_t thread_send = RT_NULL;
rt_thread_t thread_recv = RT_NULL;
rt_err_t result = RT_EOK;
result = uart_find();
if (result != RT_EOK)
{
return -RT_ERROR;
}
rx_sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);
if (rx_sem == RT_NULL)
{
LOG_E("Init sem failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
/* reinitialize */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
config.baud_rate = BAUD_RATE_115200;
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
if (result != RT_EOK)
{
LOG_E("Open uart device failed.");
uart_result = RT_FALSE;
rt_sem_delete(rx_sem);
return -RT_ERROR;
}
/* set receive callback function */
result = rt_device_set_rx_indicate(&serial->parent, uart_rx_indicate);
if (result != RT_EOK)
{
goto __exit;
}
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
if (thread_send != RT_NULL && thread_recv != RT_NULL)
{
rt_thread_startup(thread_recv);
rt_thread_startup(thread_send);
}
else
{
result = -RT_ERROR;
goto __exit;
}
while (1)
{
if (uart_result != RT_TRUE)
{
LOG_E("The test for uart dma is failure.");
result = -RT_ERROR;
goto __exit;
}
if (uart_over_flag == RT_TRUE)
{
goto __exit;
}
/* waiting for test over */
rt_thread_mdelay(5);
}
__exit:
if (rx_sem)
rt_sem_delete(rx_sem);
rt_device_close(&serial->parent);
uart_over_flag = RT_FALSE;
return result;
}
static void tc_uart_api(void)
{
rt_uint32_t times = 0;
rt_uint16_t num = 0;
while (TC_UART_SEND_TIMES - times)
{
num = (rand() % 1000) + 1;
if(uart_api(num) == RT_EOK)
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
else
{
LOG_E("uart test error");
break;
}
}
uassert_true(uart_result == RT_TRUE);
}
static rt_err_t utest_tc_init(void)
{
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rx_sem = RT_NULL;
uart_result = RT_TRUE;
uart_over_flag = RT_FALSE;
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(tc_uart_api);
}
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxnb_txb", utest_tc_init, utest_tc_cleanup, 30);
#endif /* TC_UART_USING_TC */

View File

@ -0,0 +1,294 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-16 KyleChan the first version
*/
#include <rtthread.h>
#include "utest.h"
#include <rtdevice.h>
#include <stdlib.h>
#define TC_UART_DEVICE_NAME "uart2"
#define TC_UART_SEND_TIMES 100
#ifdef UTEST_SERIAL_TC
#define TEST_UART_NAME TC_UART_DEVICE_NAME
static struct rt_serial_device *serial;
static rt_sem_t tx_sem;
static rt_sem_t rx_sem;
static rt_uint8_t uart_over_flag;
static rt_bool_t uart_result = RT_TRUE;
static rt_err_t uart_find(void)
{
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
if (serial == RT_NULL)
{
LOG_E("find %s device failed!\n", TEST_UART_NAME);
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t uart_tx_completion(rt_device_t device, void *buffer)
{
rt_sem_release(tx_sem);
return RT_EOK;
}
static rt_err_t uart_rx_indicate(rt_device_t device, rt_size_t size)
{
rt_sem_release(rx_sem);
return RT_EOK;
}
static void uart_send_entry(void *parameter)
{
rt_uint8_t *uart_write_buffer;
rt_uint16_t send_len, len = 0;
rt_err_t result;
rt_uint32_t i = 0;
send_len = *(rt_uint16_t *)parameter;
/* assign send buffer */
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
if (uart_write_buffer == RT_NULL)
{
LOG_E("Without spare memory for uart dma!");
uart_result = RT_FALSE;
return;
}
rt_memset(uart_write_buffer, 0, send_len);
for (i = 0; i < send_len; i++)
{
uart_write_buffer[i] = (rt_uint8_t)i;
}
/* send buffer */
while (send_len - len)
{
len += rt_device_write(&serial->parent, 0, uart_write_buffer + len, send_len - len);
result = rt_sem_take(tx_sem, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
LOG_E("take sem err in send.");
}
}
rt_free(uart_write_buffer);
}
static void uart_rec_entry(void *parameter)
{
rt_uint16_t rev_len;
rev_len = *(rt_uint16_t *)parameter;
rt_uint8_t *ch;
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
rt_int32_t cnt, i;
rt_uint8_t last_old_data;
rt_bool_t fisrt_flag = RT_TRUE;
rt_uint32_t all_receive_length = 0;
while (1)
{
rt_err_t result;
result = rt_sem_take(rx_sem, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
LOG_E("take sem err in recv.");
}
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
if (cnt == 0)
{
continue;
}
if (fisrt_flag != RT_TRUE)
{
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
{
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
else
{
fisrt_flag = RT_FALSE;
}
for (i = 0; i < cnt - 1; i++)
{
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
{
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
uart_result = RT_FALSE;
rt_free(ch);
return;
}
}
all_receive_length += cnt;
if (all_receive_length >= rev_len)
break;
else
last_old_data = ch[cnt - 1];
}
rt_free(ch);
uart_over_flag = RT_TRUE;
}
static rt_err_t uart_api(rt_uint16_t test_buf)
{
rt_thread_t thread_send = RT_NULL;
rt_thread_t thread_recv = RT_NULL;
rt_err_t result = RT_EOK;
uart_over_flag = RT_FALSE;
result = uart_find();
if (result != RT_EOK)
{
return -RT_ERROR;
}
rx_sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);
if (rx_sem == RT_NULL)
{
LOG_E("Init rx_sem failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
tx_sem = rt_sem_create("tx_sem", 0, RT_IPC_FLAG_PRIO);
if (tx_sem == RT_NULL)
{
LOG_E("Init tx_sem failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
/* reinitialize */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
config.baud_rate = BAUD_RATE_115200;
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING);
if (result != RT_EOK)
{
LOG_E("Open uart device failed.");
uart_result = RT_FALSE;
return -RT_ERROR;
}
/* set receive callback function */
result = rt_device_set_tx_complete(&serial->parent, uart_tx_completion);
if (result != RT_EOK)
{
goto __exit;
}
result = rt_device_set_rx_indicate(&serial->parent, uart_rx_indicate);
if (result != RT_EOK)
{
goto __exit;
}
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
if (thread_send != RT_NULL && thread_recv != RT_NULL)
{
rt_thread_startup(thread_recv);
rt_thread_startup(thread_send);
}
else
{
result = -RT_ERROR;
goto __exit;
}
while (1)
{
if (uart_result != RT_TRUE)
{
LOG_E("The test for uart dma is failure.");
result = -RT_ERROR;
goto __exit;
}
if (uart_over_flag == RT_TRUE)
{
goto __exit;
}
/* waiting for test over */
rt_thread_mdelay(5);
}
__exit:
if (tx_sem)
rt_sem_delete(tx_sem);
if (rx_sem)
rt_sem_delete(rx_sem);
rt_device_close(&serial->parent);
return result;
}
static void tc_uart_api(void)
{
rt_uint32_t times = 0;
rt_uint16_t num = 0;
while (TC_UART_SEND_TIMES - times)
{
num = (rand() % 1000) + 1;
if(uart_api(num) == RT_EOK)
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
else
{
LOG_E("uart test error");
break;
}
}
uassert_true(uart_over_flag == RT_TRUE);
}
static rt_err_t utest_tc_init(void)
{
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
tx_sem = RT_NULL;
uart_result = RT_TRUE;
uart_over_flag = RT_FALSE;
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(tc_uart_api);
}
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxnb_txnb", utest_tc_init, utest_tc_cleanup, 30);
#endif

View File

@ -0,0 +1,84 @@
menu "Kernel Testcase"
config UTEST_MEMHEAP_TC
bool "memheap stability test"
default y
depends on RT_USING_MEMHEAP
config UTEST_SMALL_MEM_TC
bool "mem test"
default y
depends on RT_USING_SMALL_MEM
config UTEST_SLAB_TC
bool "slab test"
default n
depends on RT_USING_SLAB
config UTEST_IRQ_TC
bool "IRQ test"
default n
config UTEST_SEMAPHORE_TC
bool "semaphore test"
default n
depends on RT_USING_SEMAPHORE
config UTEST_EVENT_TC
bool "event test"
default n
depends on RT_USING_EVENT
config UTEST_TIMER_TC
bool "timer test"
default n
config UTEST_MESSAGEQUEUE_TC
bool "message queue test"
default n
config UTEST_SIGNAL_TC
bool "signal test"
select RT_USING_SIGNALS
default n
config UTEST_MUTEX_TC
bool "mutex test"
default n
config UTEST_MAILBOX_TC
bool "mailbox test"
default n
config UTEST_THREAD_TC
bool "thread test"
default n
select RT_USING_TIMER_SOFT
select RT_USING_THREAD
config UTEST_DEVICE_TC
bool "device test"
default n
config UTEST_ATOMIC_TC
bool "atomic test"
default n
config UTEST_HOOKLIST_TC
bool "hook list test"
select RT_USING_HOOKLIST
default n
config UTEST_MTSAFE_KPRINT_TC
bool "mtsafe kprint test"
default n
config UTEST_SCHEDULER_TC
bool "scheduler test"
default n
if RT_USING_SMP
rsource "smp/Kconfig"
endif
endmenu

View File

@ -0,0 +1,70 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]
if GetDepend(['UTEST_MEMHEAP_TC']):
src += ['memheap_tc.c']
if GetDepend(['UTEST_SMALL_MEM_TC']):
src += ['mem_tc.c']
if GetDepend(['UTEST_SLAB_TC']):
src += ['slab_tc.c']
if GetDepend(['UTEST_IRQ_TC']):
src += ['irq_tc.c']
if GetDepend(['UTEST_SEMAPHORE_TC']):
src += ['semaphore_tc.c']
if GetDepend(['UTEST_EVENT_TC']):
src += ['event_tc.c']
if GetDepend(['UTEST_TIMER_TC']):
src += ['timer_tc.c']
if GetDepend(['UTEST_MESSAGEQUEUE_TC']):
src += ['messagequeue_tc.c']
if GetDepend(['UTEST_SIGNAL_TC']):
src += ['signal_tc.c']
if GetDepend(['UTEST_MUTEX_TC']):
src += ['mutex_tc.c', 'mutex_pi_tc.c']
if GetDepend(['UTEST_MAILBOX_TC']):
src += ['mailbox_tc.c']
if GetDepend(['UTEST_THREAD_TC']):
src += ['thread_tc.c']
if GetDepend(['UTEST_DEVICE_TC']):
src += ['device_tc.c']
if GetDepend(['UTEST_ATOMIC_TC']):
src += ['atomic_tc.c']
if GetDepend(['UTEST_HOOKLIST_TC']):
src += ['hooklist_tc.c']
if GetDepend(['UTEST_MTSAFE_KPRINT_TC']):
src += ['mtsafe_kprint_tc.c']
# Stressful testcase for scheduler (MP/UP)
if GetDepend(['UTEST_SCHEDULER_TC']):
src += ['sched_timed_sem_tc.c']
src += ['sched_timed_mtx_tc.c']
src += ['sched_mtx_tc.c']
src += ['sched_sem_tc.c', 'sched_thread_tc.c']
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
group = group + SConscript(os.path.join(item, 'SConscript'))
Return('group')

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-07-27 flybreak the first version
* 2023-03-21 WangShun add atomic test
* 2023-09-15 xqyjlj change stack size in cpu64
*/
#include <rtthread.h>
#include "utest.h"
#include "rtatomic.h"
#include <rthw.h>
#define THREAD_PRIORITY 25
#define THREAD_TIMESLICE 1
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
/* convenience macro - return either 64-bit or 32-bit value */
#define ATOMIC_WORD(val_if_64, val_if_32) \
((rt_atomic_t)((sizeof(void *) == sizeof(uint64_t)) ? (val_if_64) : (val_if_32)))
static rt_atomic_t count = 0;
static rt_sem_t sem_t;
static void test_atomic_api(void)
{
rt_atomic_t base;
rt_atomic_t oldval;
rt_atomic_t result;
/* rt_atomic_t */
uassert_true(sizeof(rt_atomic_t) == ATOMIC_WORD(sizeof(uint64_t), sizeof(uint32_t)));
/* rt_atomic_add */
base = 0;
result = rt_atomic_add(&base, 10);
uassert_true(base == 10);
uassert_true(result == 0);
/* rt_atomic_add negative */
base = 2;
result = rt_atomic_add(&base, -4);
uassert_true(base == -2);
uassert_true(result == 2);
/* rt_atomic_sub */
base = 11;
result = rt_atomic_sub(&base, 10);
uassert_true(base == 1);
uassert_true(result == 11);
/* rt_atomic_sub negative */
base = 2;
result = rt_atomic_sub(&base, -5);
uassert_true(base == 7);
uassert_true(result == 2);
/* rt_atomic_or */
base = 0xFF00;
result = rt_atomic_or(&base, 0x0F0F);
uassert_true(base == 0xFF0F);
uassert_true(result == 0xFF00);
/* rt_atomic_xor */
base = 0xFF00;
result = rt_atomic_xor(&base, 0x0F0F);
uassert_true(base == 0xF00F);
uassert_true(result == 0xFF00);
/* rt_atomic_and */
base = 0xFF00;
result = rt_atomic_and(&base, 0x0F0F);
uassert_true(base == 0x0F00);
uassert_true(result == 0xFF00);
/* rt_atomic_exchange */
base = 0xFF00;
result = rt_atomic_exchange(&base, 0x0F0F);
uassert_true(base == 0x0F0F);
uassert_true(result == 0xFF00);
/* rt_atomic_flag_test_and_set (Flag 0) */
base = 0x0;
result = rt_atomic_flag_test_and_set(&base);
uassert_true(base == 0x1);
uassert_true(result == 0x0);
/* rt_atomic_flag_test_and_set (Flag 1) */
base = 0x1;
result = rt_atomic_flag_test_and_set(&base);
uassert_true(base == 0x1);
uassert_true(result == 0x1);
/* rt_atomic_flag_clear */
base = 0x1;
rt_atomic_flag_clear(&base);
uassert_true(base == 0x0);
/* rt_atomic_load */
base = 0xFF00;
result = rt_atomic_load(&base);
uassert_true(base == 0xFF00);
uassert_true(result == 0xFF00);
/* rt_atomic_store */
base = 0xFF00;
rt_atomic_store(&base, 0x0F0F);
uassert_true(base == 0x0F0F);
/* rt_atomic_compare_exchange_strong (equal) */
base = 10;
oldval = 10;
result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
uassert_true(base == 11);
uassert_true(result == 0x1);
/* rt_atomic_compare_exchange_strong (not equal) */
base = 10;
oldval = 5;
result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
uassert_true(base == 10);
uassert_true(result == 0x0);
}
static void ture_entry(void *parameter)
{
int i;
for (i = 0; i < 1000000; i++)
{
rt_atomic_add(&count, 1);
}
rt_sem_release(sem_t);
}
static void test_atomic_add(void)
{
rt_thread_t thread;
size_t i;
sem_t = rt_sem_create("atomic_sem", 0, RT_IPC_FLAG_PRIO);
rt_atomic_store(&count, 0);
thread = rt_thread_create("t1", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(thread);
thread = rt_thread_create("t2", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(thread);
thread = rt_thread_create("t3", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(thread);
for (i = 0; i < 3; i++)
{
rt_sem_take(sem_t, RT_WAITING_FOREVER);
}
i = rt_atomic_load(&count);
uassert_true(i == 3000000);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_atomic_api);
UTEST_UNIT_RUN(test_atomic_add);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.atomic_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-05-20 Shell the first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
static void test_rt_device_find(void)
{
char _device_name[RT_NAME_MAX + 1] = {0};
rt_device_t console;
rt_device_t device1, device2, device3;
console = rt_console_get_device();
uassert_not_null(console);
rt_memcpy(_device_name, console->parent.name, RT_NAME_MAX);
/* Test finding a device */
device1 = rt_device_find(_device_name);
uassert_true(device1 == console);
/* Test finding another device */
device2 = rt_device_find(RT_CONSOLE_DEVICE_NAME);
if (rt_strcmp(RT_CONSOLE_DEVICE_NAME, _device_name) == 0)
{
uassert_true(device2 == device1);
}
else
{
uassert_not_null(device2);
uassert_true(device2 != device1);
}
/* Test finding a device 3 */
device3 = rt_device_find(console->parent.name);
uassert_true(device1 == device3);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_rt_device_find);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.device.find", utest_tc_init, utest_tc_cleanup, 5);

View File

@ -0,0 +1,346 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-08-15 liukang the first version
* 2023-09-15 xqyjlj change stack size in cpu64
*/
#include <rtthread.h>
#include "utest.h"
#include <stdlib.h>
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
#define EVENT_FLAG3 (1 << 3)
#define EVENT_FLAG5 (1 << 5)
static struct rt_event static_event = {0};
#ifdef RT_USING_HEAP
static rt_event_t dynamic_event = RT_NULL;
static rt_uint32_t dynamic_event_recv_thread_finish = 0, dynamic_event_send_thread_finish = 0;
rt_align(RT_ALIGN_SIZE)
static char thread3_stack[UTEST_THR_STACK_SIZE];
static struct rt_thread thread3;
rt_align(RT_ALIGN_SIZE)
static char thread4_stack[UTEST_THR_STACK_SIZE];
static struct rt_thread thread4;
#endif /* RT_USING_HEAP */
static rt_uint32_t recv_event_times1 = 0, recv_event_times2 = 0;
static rt_uint32_t static_event_recv_thread_finish = 0, static_event_send_thread_finish = 0;
rt_align(RT_ALIGN_SIZE)
static char thread1_stack[UTEST_THR_STACK_SIZE];
static struct rt_thread thread1;
rt_align(RT_ALIGN_SIZE)
static char thread2_stack[UTEST_THR_STACK_SIZE];
static struct rt_thread thread2;
#define THREAD_PRIORITY 9
#define THREAD_TIMESLICE 5
static void test_event_init(void)
{
rt_err_t result;
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_event_detach(&static_event);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_event_detach(&static_event);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void test_event_detach(void)
{
rt_err_t result = RT_EOK;
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_event_detach(&static_event);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void thread1_recv_static_event(void *param)
{
rt_uint32_t e;
if (rt_event_recv(&static_event, (EVENT_FLAG3 | EVENT_FLAG5),
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &e) != RT_EOK)
{
return;
}
recv_event_times1 = e;
rt_thread_mdelay(50);
if (rt_event_recv(&static_event, (EVENT_FLAG3 | EVENT_FLAG5),
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &e) != RT_EOK)
{
return;
}
recv_event_times2 = e;
static_event_recv_thread_finish = 1;
}
static void thread2_send_static_event(void *param)
{
rt_event_send(&static_event, EVENT_FLAG3);
rt_thread_mdelay(10);
rt_event_send(&static_event, EVENT_FLAG5);
rt_thread_mdelay(10);
rt_event_send(&static_event, EVENT_FLAG3);
static_event_send_thread_finish = 1;
}
static void test_static_event_send_recv(void)
{
rt_err_t result = RT_EOK;
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
if (result != RT_EOK)
{
uassert_false(1);
}
rt_thread_init(&thread1,
"thread1",
thread1_recv_static_event,
RT_NULL,
&thread1_stack[0],
sizeof(thread1_stack),
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread2,
"thread2",
thread2_send_static_event,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
while (static_event_recv_thread_finish != 1 || static_event_send_thread_finish != 1)
{
rt_thread_delay(1);
}
if (recv_event_times1 == EVENT_FLAG3 && recv_event_times2 == (EVENT_FLAG3 | EVENT_FLAG5))
{
if (rt_event_detach(&static_event) != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
else
{
if (rt_event_detach(&static_event) != RT_EOK)
{
uassert_false(1);
}
uassert_false(1);
}
return;
}
#ifdef RT_USING_HEAP
static void test_event_create(void)
{
rt_err_t result = RT_EOK;
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_FIFO);
if (dynamic_event == RT_NULL)
{
uassert_false(1);
}
result = rt_event_delete(dynamic_event);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void test_event_delete(void)
{
rt_err_t result;
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_FIFO);
if (dynamic_event == RT_NULL)
{
uassert_false(1);
}
result = rt_event_delete(dynamic_event);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void thread3_recv_dynamic_event(void *param)
{
rt_uint32_t e;
if (rt_event_recv(dynamic_event, (EVENT_FLAG3 | EVENT_FLAG5),
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &e) != RT_EOK)
{
return;
}
recv_event_times1 = e;
rt_thread_mdelay(50);
if (rt_event_recv(dynamic_event, (EVENT_FLAG3 | EVENT_FLAG5),
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &e) != RT_EOK)
{
return;
}
recv_event_times2 = e;
dynamic_event_recv_thread_finish = 1;
}
static void thread4_send_dynamic_event(void *param)
{
rt_event_send(dynamic_event, EVENT_FLAG3);
rt_thread_mdelay(10);
rt_event_send(dynamic_event, EVENT_FLAG5);
rt_thread_mdelay(10);
rt_event_send(dynamic_event, EVENT_FLAG3);
dynamic_event_send_thread_finish = 1;
}
static void test_dynamic_event_send_recv(void)
{
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_PRIO);
if (dynamic_event == RT_NULL)
{
uassert_false(1);
}
rt_thread_init(&thread3,
"thread3",
thread3_recv_dynamic_event,
RT_NULL,
&thread3_stack[0],
sizeof(thread3_stack),
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&thread3);
rt_thread_init(&thread4,
"thread4",
thread4_send_dynamic_event,
RT_NULL,
&thread4_stack[0],
sizeof(thread4_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread4);
while (dynamic_event_recv_thread_finish != 1 || dynamic_event_send_thread_finish != 1)
{
rt_thread_delay(1);
}
if (recv_event_times1 == EVENT_FLAG3 && recv_event_times2 == (EVENT_FLAG3 | EVENT_FLAG5))
{
if (rt_event_delete(dynamic_event) != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
else
{
if (rt_event_delete(dynamic_event) != RT_EOK)
{
uassert_false(1);
}
uassert_false(1);
}
return;
}
#endif
static rt_err_t utest_tc_init(void)
{
static_event_recv_thread_finish = 0;
static_event_send_thread_finish = 0;
#ifdef RT_USING_HEAP
dynamic_event_recv_thread_finish = 0;
dynamic_event_send_thread_finish = 0;
#endif
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_event_init);
UTEST_UNIT_RUN(test_event_detach);
UTEST_UNIT_RUN(test_static_event_send_recv);
#ifdef RT_USING_HEAP
UTEST_UNIT_RUN(test_event_create);
UTEST_UNIT_RUN(test_event_delete);
UTEST_UNIT_RUN(test_dynamic_event_send_recv);
#endif
}
UTEST_TC_EXPORT(testcase, "src.ipc.event_tc", utest_tc_init, utest_tc_cleanup, 60);

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-12-22 Shell Support hook list
*/
#include <rtthread.h>
#include "rtconfig.h"
#include "utest.h"
#include "utest_assert.h"
static int hooker1_ent_count;
static int hooker2_ent_count;
static struct rt_thread thr_tobe_inited;
static void thread_inited_hooker1(rt_thread_t thread)
{
LOG_D("%s: count %d", __func__, hooker1_ent_count);
hooker1_ent_count += 1;
}
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_thread_inited, hooker1_node, thread_inited_hooker1);
static void thread_inited_hooker2(rt_thread_t thread)
{
LOG_D("%s: count %d", __func__, hooker2_ent_count);
hooker2_ent_count += 1;
}
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_thread_inited, hooker2_node, thread_inited_hooker2);
static char _thr_stack[UTEST_THR_STACK_SIZE];
static void thr_tobe_inited_entry(void *param)
{
rt_kprintf("Hello!\n");
}
static void hooklist_test(void)
{
hooker1_ent_count = 0;
hooker2_ent_count = 0;
rt_thread_inited_sethook(&hooker1_node);
rt_thread_inited_sethook(&hooker2_node);
/* run 1 */
rt_thread_init(&thr_tobe_inited,
"thr_tobe_inited",
thr_tobe_inited_entry,
NULL,
_thr_stack,
sizeof(_thr_stack),
25,
100);
uassert_int_equal(hooker1_ent_count, 1);
uassert_int_equal(hooker2_ent_count, 1);
rt_thread_detach(&thr_tobe_inited);
rt_thread_mdelay(1); /* wait recycling done */
/* run 2 */
rt_thread_inited_rmhook(&hooker2_node);
rt_thread_init(&thr_tobe_inited,
"thr_tobe_inited",
thr_tobe_inited_entry,
NULL,
_thr_stack,
sizeof(_thr_stack),
25,
100);
uassert_int_equal(hooker1_ent_count, 2);
uassert_int_equal(hooker2_ent_count, 1);
}
static rt_err_t utest_tc_init(void)
{
hooker1_ent_count = 0;
hooker2_ent_count = 0;
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_thread_detach(&thr_tobe_inited);
rt_thread_inited_rmhook(&hooker1_node);
rt_thread_inited_rmhook(&hooker2_node);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(hooklist_test);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.hooklist_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-08-15 supperthomas add irq_test
*/
#include <rtthread.h>
#include "utest.h"
#include "rthw.h"
#define UTEST_NAME "irq_tc"
static volatile uint32_t irq_count = 0;
static volatile uint32_t max_get_nest_count = 0;
static void irq_callback()
{
if(rt_interrupt_get_nest() > max_get_nest_count)
{
max_get_nest_count = rt_interrupt_get_nest();
}
irq_count ++;
}
static void irq_test(void)
{
irq_count = 0;
rt_interrupt_enter_sethook(irq_callback);
rt_interrupt_leave_sethook(irq_callback);
rt_thread_mdelay(2);
LOG_D("%s test irq_test! irq_count %d max_get_nest_count %d\n", UTEST_NAME, irq_count, max_get_nest_count);
uassert_int_not_equal(0, irq_count);
uassert_int_not_equal(0, max_get_nest_count);
rt_interrupt_enter_sethook(RT_NULL);
rt_interrupt_leave_sethook(RT_NULL);
LOG_D("irq_test OK!\n");
}
static rt_err_t utest_tc_init(void)
{
irq_count = 0;
max_get_nest_count = 0;
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void interrupt_test(void)
{
rt_base_t level;
uint32_t i = 1000;
rt_interrupt_enter_sethook(irq_callback);
rt_interrupt_leave_sethook(irq_callback);
irq_count = 0;
level = rt_hw_interrupt_disable();
while(i)
{
i --;
}
uassert_int_equal(0, irq_count);
rt_hw_interrupt_enable(level);
rt_interrupt_enter_sethook(RT_NULL);
rt_interrupt_leave_sethook(RT_NULL);
}
static void testcase(void)
{
UTEST_UNIT_RUN(irq_test);
UTEST_UNIT_RUN(interrupt_test);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.irq_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,374 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-09-08 liukang the first version
* 2023-09-15 xqyjlj change stack size in cpu64
*/
#include <rtthread.h>
#include "utest.h"
#include <stdlib.h>
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
static struct rt_mailbox test_static_mb;
static char mb_pool[128];
static rt_mailbox_t test_dynamic_mb;
static uint8_t static_mb_recv_thread_finish, static_mb_send_thread_finish;
static uint8_t dynamic_mb_recv_thread_finish, dynamic_mb_send_thread_finish;
rt_align(RT_ALIGN_SIZE)
static char thread1_stack[UTEST_THR_STACK_SIZE];
static struct rt_thread thread1;
rt_align(RT_ALIGN_SIZE)
static char thread2_stack[UTEST_THR_STACK_SIZE];
static struct rt_thread thread2;
#define THREAD_PRIORITY 9
#define THREAD_TIMESLICE 5
static rt_thread_t mb_send = RT_NULL;
static rt_thread_t mb_recv = RT_NULL;
static rt_uint8_t mb_send_str1[] = "this is first mail!";
static rt_uint8_t mb_send_str2[] = "this is second mail!";
static rt_uint8_t mb_send_str3[] = "this is thirdy mail!";
static rt_uint8_t *mb_recv_str1;
static rt_uint8_t *mb_recv_str2;
static rt_uint8_t *mb_recv_str3;
static void test_mailbox_init(void)
{
rt_err_t result;
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_mb_detach(&test_static_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_mb_detach(&test_static_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void test_mailbox_deatch(void)
{
rt_err_t result;
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_mb_detach(&test_static_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
if (result != RT_EOK)
{
uassert_false(1);
}
result = rt_mb_detach(&test_static_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void test_mailbox_create(void)
{
rt_err_t result;
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
if (test_dynamic_mb == RT_NULL)
{
uassert_false(1);
}
result = rt_mb_delete(test_dynamic_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
if (test_dynamic_mb == RT_NULL)
{
uassert_false(1);
}
result = rt_mb_delete(test_dynamic_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void test_mailbox_delete(void)
{
rt_err_t result;
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
if (test_dynamic_mb == RT_NULL)
{
uassert_false(1);
}
result = rt_mb_delete(test_dynamic_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
if (test_dynamic_mb == RT_NULL)
{
uassert_false(1);
}
result = rt_mb_delete(test_dynamic_mb);
if (result != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void thread2_send_static_mb(void *arg)
{
rt_err_t res = RT_EOK;
res = rt_mb_send(&test_static_mb, (rt_ubase_t)&mb_send_str1);
if (res != RT_EOK)
{
uassert_false(1);
}
rt_thread_mdelay(100);
res = rt_mb_send_wait(&test_static_mb, (rt_ubase_t)&mb_send_str2, 10);
if (res != RT_EOK)
{
uassert_false(1);
}
rt_thread_mdelay(100);
res = rt_mb_urgent(&test_static_mb, (rt_ubase_t)&mb_send_str3);
if (res != RT_EOK)
{
uassert_false(1);
}
static_mb_send_thread_finish = 1;
}
static void thread1_recv_static_mb(void *arg)
{
rt_err_t result = RT_EOK;
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str1, RT_WAITING_FOREVER);
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str1, (const char *)mb_send_str1) != 0)
{
uassert_false(1);
}
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str2, RT_WAITING_FOREVER);
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str2, (const char *)mb_send_str2) != 0)
{
uassert_false(1);
}
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str3, RT_WAITING_FOREVER);
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str3, (const char *)mb_send_str3) != 0)
{
uassert_false(1);
}
static_mb_recv_thread_finish = 1;
}
static void test_static_mailbox_send_recv(void)
{
rt_err_t result;
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
uassert_false(1);
}
rt_thread_init(&thread1,
"thread1",
thread1_recv_static_mb,
RT_NULL,
&thread1_stack[0],
sizeof(thread1_stack),
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread2,
"thread2",
thread2_send_static_mb,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
while (static_mb_recv_thread_finish != 1 || static_mb_send_thread_finish != 1)
{
rt_thread_delay(1);
}
if (rt_mb_detach(&test_static_mb) != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static void thread4_send_dynamic_mb(void *arg)
{
rt_err_t res = RT_EOK;
res = rt_mb_send(test_dynamic_mb, (rt_ubase_t)&mb_send_str1);
if (res != RT_EOK)
{
uassert_false(1);
}
rt_thread_mdelay(100);
res = rt_mb_send_wait(test_dynamic_mb, (rt_ubase_t)&mb_send_str2, 10);
if (res != RT_EOK)
{
uassert_false(1);
}
rt_thread_mdelay(100);
res = rt_mb_urgent(test_dynamic_mb, (rt_ubase_t)&mb_send_str3);
if (res != RT_EOK)
{
uassert_false(1);
}
dynamic_mb_send_thread_finish = 1;
}
static void thread3_recv_dynamic_mb(void *arg)
{
rt_err_t result = RT_EOK;
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str1, RT_WAITING_FOREVER);
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str1, (const char *)mb_send_str1) != 0)
{
uassert_false(1);
}
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str2, RT_WAITING_FOREVER);
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str2, (const char *)mb_send_str2) != 0)
{
uassert_false(1);
}
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str3, RT_WAITING_FOREVER);
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str3, (const char *)mb_send_str3) != 0)
{
uassert_false(1);
}
dynamic_mb_recv_thread_finish = 1;
}
static void test_dynamic_mailbox_send_recv(void)
{
test_dynamic_mb = rt_mb_create("mbt", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
if (test_dynamic_mb == RT_NULL)
{
uassert_false(1);
}
mb_recv = rt_thread_create("mb_recv_thread",
thread3_recv_dynamic_mb,
RT_NULL,
UTEST_THR_STACK_SIZE,
THREAD_PRIORITY - 1,
THREAD_TIMESLICE);
if (mb_recv == RT_NULL)
{
uassert_false(1);
}
rt_thread_startup(mb_recv);
mb_send = rt_thread_create("mb_send_thread",
thread4_send_dynamic_mb,
RT_NULL,
UTEST_THR_STACK_SIZE,
THREAD_PRIORITY - 1,
THREAD_TIMESLICE);
if (mb_send == RT_NULL)
{
uassert_false(1);
}
rt_thread_startup(mb_send);
while (dynamic_mb_recv_thread_finish != 1 || dynamic_mb_send_thread_finish != 1)
{
rt_thread_delay(1);
}
if (rt_mb_delete(test_dynamic_mb) != RT_EOK)
{
uassert_false(1);
}
uassert_true(1);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_mailbox_init);
UTEST_UNIT_RUN(test_mailbox_deatch);
UTEST_UNIT_RUN(test_mailbox_create);
UTEST_UNIT_RUN(test_mailbox_delete);
UTEST_UNIT_RUN(test_static_mailbox_send_recv);
UTEST_UNIT_RUN(test_dynamic_mailbox_send_recv);
}
UTEST_TC_EXPORT(testcase, "src.ipc.mailbox_tc", utest_tc_init, utest_tc_cleanup, 60);

View File

@ -0,0 +1,585 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-10-14 tyx the first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
struct rt_small_mem_item
{
rt_ubase_t pool_ptr; /**< small memory object addr */
rt_size_t next; /**< next free item */
rt_size_t prev; /**< prev free item */
#ifdef RT_USING_MEMTRACE
#ifdef ARCH_CPU_64BIT
rt_uint8_t thread[8]; /**< thread name */
#else
rt_uint8_t thread[4]; /**< thread name */
#endif /* ARCH_CPU_64BIT */
#endif /* RT_USING_MEMTRACE */
};
struct rt_small_mem
{
struct rt_memory parent; /**< inherit from rt_memory */
rt_uint8_t *heap_ptr; /**< pointer to the heap */
struct rt_small_mem_item *heap_end;
struct rt_small_mem_item *lfree;
rt_size_t mem_size_aligned; /**< aligned memory size */
};
#define MEM_SIZE(_heap, _mem) \
(((struct rt_small_mem_item *)(_mem))->next - ((rt_ubase_t)(_mem) - \
(rt_ubase_t)((_heap)->heap_ptr)) - RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE))
#define TEST_MEM_SIZE 1024
static rt_size_t max_block(struct rt_small_mem *heap)
{
struct rt_small_mem_item *mem;
rt_size_t max = 0, size;
for (mem = (struct rt_small_mem_item *)heap->heap_ptr;
mem != heap->heap_end;
mem = (struct rt_small_mem_item *)&heap->heap_ptr[mem->next])
{
if (((rt_ubase_t)mem->pool_ptr & 0x1) == 0)
{
size = MEM_SIZE(heap, mem);
if (size > max)
{
max = size;
}
}
}
return max;
}
static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size)
{
while (size-- != 0)
{
if (*(rt_uint8_t *)ptr != v)
return *(rt_uint8_t *)ptr - v;
}
return 0;
}
struct mem_test_context
{
void *ptr;
rt_size_t size;
rt_uint8_t magic;
};
static void mem_functional_test(void)
{
rt_size_t total_size;
rt_uint8_t *buf;
struct rt_small_mem *heap;
rt_uint8_t magic = __LINE__;
/* Prepare test memory */
buf = rt_malloc(TEST_MEM_SIZE);
uassert_not_null(buf);
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
/* small heap init */
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
/* get total size */
total_size = max_block(heap);
uassert_int_not_equal(total_size, 0);
/*
* Allocate all memory at a time and test whether
* the memory allocation release function is effective
*/
{
struct mem_test_context ctx;
ctx.magic = magic++;
ctx.size = max_block(heap);
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
uassert_not_null(ctx.ptr);
rt_memset(ctx.ptr, ctx.magic, ctx.size);
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
rt_smem_free(ctx.ptr);
uassert_int_equal(max_block(heap), total_size);
}
/*
* Apply for memory release sequentially and
* test whether memory block merging is effective
*/
{
rt_size_t i, max_free = 0;
struct mem_test_context ctx[3];
/* alloc mem */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
ctx[i].magic = magic++;
ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
uassert_not_null(ctx[i].ptr);
rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
}
/* All memory has been applied. The remaining memory should be 0 */
uassert_int_equal(max_block(heap), 0);
/* Verify that the memory data is correct */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
}
/* Sequential memory release */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
rt_smem_free(ctx[i].ptr);
max_free += ctx[i].size;
uassert_true(max_block(heap) >= max_free);
}
/* Check whether the memory is fully merged */
uassert_int_equal(max_block(heap), total_size);
}
/*
* Apply for memory release at an interval to
* test whether memory block merging is effective
*/
{
rt_size_t i, max_free = 0;
struct mem_test_context ctx[3];
/* alloc mem */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
ctx[i].magic = magic++;
ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
uassert_not_null(ctx[i].ptr);
rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
}
/* All memory has been applied. The remaining memory should be 0 */
uassert_int_equal(max_block(heap), 0);
/* Verify that the memory data is correct */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
}
/* Release even address */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
if (i % 2 == 0)
{
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
rt_smem_free(ctx[i].ptr);
uassert_true(max_block(heap) >= ctx[0].size);
}
}
/* Release odd addresses and merge memory blocks */
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
{
if (i % 2 != 0)
{
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
rt_smem_free(ctx[i].ptr);
max_free += ctx[i - 1].size + ctx[i + 1].size;
uassert_true(max_block(heap) >= max_free);
}
}
/* Check whether the memory is fully merged */
uassert_int_equal(max_block(heap), total_size);
}
/* mem realloc test,Small - > Large */
{
/* Request a piece of memory for subsequent reallocation operations */
struct mem_test_context ctx[3];
ctx[0].magic = magic++;
ctx[0].size = max_block(heap) / 3;
ctx[0].ptr = rt_smem_alloc(&heap->parent, ctx[0].size);
uassert_not_null(ctx[0].ptr);
rt_memset(ctx[0].ptr, ctx[0].magic, ctx[0].size);
/* Apply for a small piece of memory and split the continuous memory */
ctx[1].magic = magic++;
ctx[1].size = RT_ALIGN_SIZE;
ctx[1].ptr = rt_smem_alloc(&heap->parent, ctx[1].size);
uassert_not_null(ctx[1].ptr);
rt_memset(ctx[1].ptr, ctx[1].magic, ctx[1].size);
/* Check whether the maximum memory block is larger than the first piece of memory */
uassert_true(max_block(heap) > ctx[0].size);
/* Reallocate the first piece of memory */
ctx[2].magic = magic++;
ctx[2].size = max_block(heap);
ctx[2].ptr = rt_smem_realloc(&heap->parent, ctx[0].ptr, ctx[2].size);
uassert_not_null(ctx[2].ptr);
uassert_int_not_equal(ctx[0].ptr, ctx[2].ptr);
uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[0].magic, ctx[0].size), 0);
rt_memset(ctx[2].ptr, ctx[2].magic, ctx[2].size);
/* Free the second piece of memory */
uassert_int_equal(_mem_cmp(ctx[1].ptr, ctx[1].magic, ctx[1].size), 0);
rt_smem_free(ctx[1].ptr);
/* Free reallocated memory */
uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[2].magic, ctx[2].size), 0);
rt_smem_free(ctx[2].ptr);
/* Check memory integrity */
uassert_int_equal(max_block(heap), total_size);
}
/* mem realloc test,Large - > Small */
{
rt_size_t max_free;
struct mem_test_context ctx;
/* alloc a piece of memory */
ctx.magic = magic++;
ctx.size = max_block(heap) / 2;
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
uassert_not_null(ctx.ptr);
rt_memset(ctx.ptr, ctx.magic, ctx.size);
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
/* Get remaining memory */
max_free = max_block(heap);
/* Change memory size */
ctx.size = ctx.size / 2;
uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
/* Get remaining size */
uassert_true(max_block(heap) > max_free);
/* Free memory */
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
rt_smem_free(ctx.ptr);
/* Check memory integrity */
uassert_int_equal(max_block(heap), total_size);
}
/* mem realloc test,equal */
{
rt_size_t max_free;
struct mem_test_context ctx;
/* alloc a piece of memory */
ctx.magic = magic++;
ctx.size = max_block(heap) / 2;
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
uassert_not_null(ctx.ptr);
rt_memset(ctx.ptr, ctx.magic, ctx.size);
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
/* Get remaining memory */
max_free = max_block(heap);
/* Do not change memory size */
uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
/* Get remaining size */
uassert_true(max_block(heap) == max_free);
/* Free memory */
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
rt_smem_free(ctx.ptr);
/* Check memory integrity */
uassert_int_equal(max_block(heap), total_size);
}
/* small heap deinit */
rt_smem_detach(&heap->parent);
/* release test resources */
rt_free(buf);
}
struct mem_alloc_context
{
rt_list_t node;
rt_size_t size;
rt_uint8_t magic;
};
struct mem_alloc_head
{
rt_list_t list;
rt_size_t count;
rt_tick_t start;
rt_tick_t end;
rt_tick_t interval;
};
#define MEM_RANG_ALLOC_BLK_MIN 2
#define MEM_RANG_ALLOC_BLK_MAX 5
#define MEM_RANG_ALLOC_TEST_TIME 5
static void mem_alloc_test(void)
{
struct mem_alloc_head head;
rt_uint8_t *buf;
struct rt_small_mem *heap;
rt_size_t total_size, size;
struct mem_alloc_context *ctx;
/* init */
rt_list_init(&head.list);
head.count = 0;
head.start = rt_tick_get();
head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
head.interval = (head.end - head.start) / 20;
buf = rt_malloc(TEST_MEM_SIZE);
uassert_not_null(buf);
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
total_size = max_block(heap);
uassert_int_not_equal(total_size, 0);
/* test run */
while (head.end - head.start < RT_TICK_MAX / 2)
{
if (rt_tick_get() - head.start >= head.interval)
{
head.start = rt_tick_get();
rt_kprintf("#");
}
/* %60 probability to perform alloc operation */
if (rand() % 10 >= 4)
{
size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
size *= sizeof(struct mem_alloc_context);
ctx = rt_smem_alloc(&heap->parent, size);
if (ctx == RT_NULL)
{
if (head.count == 0)
{
break;
}
size = head.count / 2;
while (size != head.count)
{
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
rt_list_remove(&ctx->node);
if (ctx->size > sizeof(*ctx))
{
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
{
uassert_true(0);
}
}
rt_memset(ctx, 0xAA, ctx->size);
rt_smem_free(ctx);
head.count --;
}
continue;
}
if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx)
{
uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx);
}
rt_memset(ctx, 0, size);
rt_list_init(&ctx->node);
ctx->size = size;
ctx->magic = rand() & 0xff;
if (ctx->size > sizeof(*ctx))
{
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
}
rt_list_insert_after(&head.list, &ctx->node);
head.count += 1;
}
else
{
if (!rt_list_isempty(&head.list))
{
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
rt_list_remove(&ctx->node);
if (ctx->size > sizeof(*ctx))
{
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
{
uassert_true(0);
}
}
rt_memset(ctx, 0xAA, ctx->size);
rt_smem_free(ctx);
head.count --;
}
}
}
while (!rt_list_isempty(&head.list))
{
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
rt_list_remove(&ctx->node);
if (ctx->size > sizeof(*ctx))
{
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
{
uassert_true(0);
}
}
rt_memset(ctx, 0xAA, ctx->size);
rt_smem_free(ctx);
head.count --;
}
uassert_int_equal(head.count, 0);
uassert_int_equal(max_block(heap), total_size);
/* small heap deinit */
rt_smem_detach(&heap->parent);
/* release test resources */
rt_free(buf);
}
#define MEM_RANG_REALLOC_BLK_MIN 0
#define MEM_RANG_REALLOC_BLK_MAX 5
#define MEM_RANG_REALLOC_TEST_TIME 5
struct mem_realloc_context
{
rt_size_t size;
rt_uint8_t magic;
};
struct mem_realloc_head
{
struct mem_realloc_context **ctx_tab;
rt_size_t count;
rt_tick_t start;
rt_tick_t end;
rt_tick_t interval;
};
static void mem_realloc_test(void)
{
struct mem_realloc_head head;
rt_uint8_t *buf;
struct rt_small_mem *heap;
rt_size_t total_size, size, idx;
struct mem_realloc_context *ctx;
int res;
size = RT_ALIGN(sizeof(struct mem_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
size = TEST_MEM_SIZE / size;
/* init */
head.ctx_tab = RT_NULL;
head.count = size;
head.start = rt_tick_get();
head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
head.interval = (head.end - head.start) / 20;
buf = rt_malloc(TEST_MEM_SIZE);
uassert_not_null(buf);
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
total_size = max_block(heap);
uassert_int_not_equal(total_size, 0);
/* init ctx tab */
size = head.count * sizeof(struct mem_realloc_context *);
head.ctx_tab = rt_smem_alloc(&heap->parent, size);
uassert_not_null(head.ctx_tab);
rt_memset(head.ctx_tab, 0, size);
/* test run */
while (head.end - head.start < RT_TICK_MAX / 2)
{
if (rt_tick_get() - head.start >= head.interval)
{
head.start = rt_tick_get();
rt_kprintf("#");
}
size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
size *= sizeof(struct mem_realloc_context);
idx = rand() % head.count;
ctx = rt_smem_realloc(&heap->parent, head.ctx_tab[idx], size);
if (ctx == RT_NULL)
{
if (size == 0)
{
if (head.ctx_tab[idx])
{
head.ctx_tab[idx] = RT_NULL;
}
}
else
{
for (idx = 0; idx < head.count; idx++)
{
ctx = head.ctx_tab[idx];
if (rand() % 2 && ctx)
{
if (ctx->size > sizeof(*ctx))
{
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
if (res != 0)
{
uassert_int_equal(res, 0);
}
}
rt_memset(ctx, 0xAA, ctx->size);
rt_smem_realloc(&heap->parent, ctx, 0);
head.ctx_tab[idx] = RT_NULL;
}
}
}
continue;
}
/* check mem */
if (head.ctx_tab[idx] != RT_NULL)
{
res = 0;
if (ctx->size < size)
{
if (ctx->size > sizeof(*ctx))
{
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
}
}
else
{
if (size > sizeof(*ctx))
{
res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx));
}
}
if (res != 0)
{
uassert_int_equal(res, 0);
}
}
/* init mem */
ctx->magic = rand() & 0xff;
ctx->size = size;
if (ctx->size > sizeof(*ctx))
{
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
}
head.ctx_tab[idx] = ctx;
}
/* free all mem */
for (idx = 0; idx < head.count; idx++)
{
ctx = head.ctx_tab[idx];
if (ctx == RT_NULL)
{
continue;
}
if (ctx->size > sizeof(*ctx))
{
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
if (res != 0)
{
uassert_int_equal(res, 0);
}
}
rt_memset(ctx, 0xAA, ctx->size);
rt_smem_realloc(&heap->parent, ctx, 0);
head.ctx_tab[idx] = RT_NULL;
}
uassert_int_not_equal(max_block(heap), total_size);
/* small heap deinit */
rt_smem_detach(&heap->parent);
/* release test resources */
rt_free(buf);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(mem_functional_test);
UTEST_UNIT_RUN(mem_alloc_test);
UTEST_UNIT_RUN(mem_realloc_test);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.mem_tc", utest_tc_init, utest_tc_cleanup, 20);

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-01-16 flybreak the first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
#define HEAP_SIZE (64 * 1024)
#define HEAP_ALIGN (4)
#define SLICE_NUM (40)
#define TEST_TIMES (100000)
#define HEAP_NAME "heap1"
#define SLICE_SIZE_MAX (HEAP_SIZE/SLICE_NUM)
static void memheap_test(void)
{
struct rt_memheap heap1;
void * ptr_start;
void *ptr[SLICE_NUM];
int i, cnt = 0;
/* init heap */
ptr_start = rt_malloc_align(HEAP_SIZE, HEAP_ALIGN);
if (ptr_start == RT_NULL)
{
rt_kprintf("totle size too big,can not malloc memory!");
return;
}
rt_memheap_init(&heap1, HEAP_NAME, ptr_start, HEAP_SIZE);
/* test start */
for (i = 0; i < SLICE_NUM; i++)
{
ptr[i] = 0;
}
/* test alloc */
for (i = 0; i < SLICE_NUM; i++)
{
rt_uint32_t slice_size = rand() % SLICE_SIZE_MAX;
ptr[i] = rt_memheap_alloc(&heap1, slice_size);
}
/* test realloc */
while (cnt < TEST_TIMES)
{
rt_uint32_t slice_size = rand() % SLICE_SIZE_MAX;
rt_uint32_t ptr_index = rand() % SLICE_NUM;
rt_uint32_t operation = rand() % 2;
if (ptr[ptr_index])
{
if (operation == 0) /* free and malloc */
{
rt_memheap_free(ptr[ptr_index]);
ptr[ptr_index] = rt_memheap_alloc(&heap1, slice_size);
}
else /* realloc */
{
ptr[ptr_index] = rt_memheap_realloc(&heap1, ptr[ptr_index], slice_size);
}
}
cnt ++;
if (cnt % (TEST_TIMES / 10) == 0)
{
rt_kprintf(">");
}
}
rt_kprintf("test OK!\n");
/* test end */
rt_memheap_detach(&heap1);
rt_free_align((void *)ptr_start);
}
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(memheap_test);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.memheap_tc", utest_tc_init, utest_tc_cleanup, 10);

View File

@ -0,0 +1,234 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-08-28 Sherman the first version
* 2023-09-15 xqyjlj change stack size in cpu64
* fix in smp
*/
#include <rtthread.h>
#include "utest.h"
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
#define MSG_SIZE 4
#define MAX_MSGS 5
static struct rt_messagequeue static_mq;
static rt_uint8_t mq_buf[RT_MQ_BUF_SIZE(MSG_SIZE, MAX_MSGS)];
static struct rt_thread mq_send_thread;
static struct rt_thread mq_recv_thread;
static rt_uint8_t mq_send_stack[UTEST_THR_STACK_SIZE];
static rt_uint8_t mq_recv_stack[UTEST_THR_STACK_SIZE];
static struct rt_event finish_e;
#define MQSEND_FINISH 0x01
#define MQRECV_FINIHS 0x02
#ifdef RT_USING_HEAP
static rt_mq_t dynamic_mq;
#endif /* RT_USING_HEAP */
static void test_mq_init(void)
{
rt_err_t ret;
ret = rt_mq_init(&static_mq,"testmq1", mq_buf, MSG_SIZE, sizeof(mq_buf), RT_IPC_FLAG_FIFO);
uassert_true(ret == RT_EOK);
}
static void test_mq_create(void)
{
#ifdef RT_USING_HEAP
dynamic_mq = rt_mq_create("testmq2", MSG_SIZE, MAX_MSGS, RT_IPC_FLAG_FIFO);
uassert_true(dynamic_mq != RT_NULL);
#endif /* RT_USING_HEAP */
}
static void mq_send_case(rt_mq_t testmq)
{
rt_uint32_t send_buf[MAX_MSGS+1] = {0};
rt_err_t ret = RT_EOK;
for (int var = 0; var < MAX_MSGS; ++var)
{
send_buf[var] = var + 1;
ret = rt_mq_send_wait(testmq, &send_buf[var], sizeof(send_buf[0]), RT_WAITING_FOREVER);
uassert_true(ret == RT_EOK);
}
send_buf[MAX_MSGS] = MAX_MSGS + 1;
ret = rt_mq_send(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]));
uassert_true(ret == -RT_EFULL);
ret = rt_mq_send_wait(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]), RT_WAITING_FOREVER);
uassert_true(ret == RT_EOK);
while (testmq->entry != 0)
{
rt_thread_delay(100);
}
ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
uassert_true(ret == RT_EOK);
ret = rt_mq_send(testmq, &send_buf[2], sizeof(send_buf[0]));
uassert_true(ret == RT_EOK);
ret = rt_mq_urgent(testmq, &send_buf[0], sizeof(send_buf[0]));
uassert_true(ret == RT_EOK);
while (testmq->entry != 0)
{
rt_thread_delay(100);
}
#ifdef RT_USING_MESSAGEQUEUE_PRIORITY
ret = rt_mq_send_wait_prio(testmq, &send_buf[3], sizeof(send_buf[0]), 3, 0, RT_UNINTERRUPTIBLE);
uassert_true(ret == RT_EOK);
ret = rt_mq_send_wait_prio(testmq, &send_buf[0], sizeof(send_buf[0]), 0, 0, RT_UNINTERRUPTIBLE);
uassert_true(ret == RT_EOK);
ret = rt_mq_send_wait_prio(testmq, &send_buf[2], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
uassert_true(ret == RT_EOK);
ret = rt_mq_send_wait_prio(testmq, &send_buf[4], sizeof(send_buf[0]), 4, 0, RT_UNINTERRUPTIBLE);
uassert_true(ret == RT_EOK);
ret = rt_mq_send_wait_prio(testmq, &send_buf[1], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
uassert_true(ret == RT_EOK);
while (testmq->entry != 0)
{
rt_thread_delay(100);
}
#endif
ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
uassert_true(ret == RT_EOK);
ret = rt_mq_control(testmq, RT_IPC_CMD_RESET, RT_NULL);
uassert_true(ret == RT_EOK);
uassert_true(testmq->entry == 0);
}
static void mq_send_entry(void *param)
{
mq_send_case(&static_mq);
#ifdef RT_USING_HEAP
if(dynamic_mq != RT_NULL)
{
mq_send_case(dynamic_mq);
}
#endif /* RT_USING_HEAP */
rt_event_send(&finish_e, MQSEND_FINISH);
}
static void mq_recv_case(rt_mq_t testmq)
{
rt_uint32_t recv_buf[MAX_MSGS+1] = {0};
rt_ssize_t ret = RT_EOK;
for (int var = 0; var < MAX_MSGS + 1; ++var)
{
ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
uassert_true(ret >= 0);
uassert_true(recv_buf[var] == (var + 1));
}
for (int var = 0; var < 3; ++var)
{
ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
uassert_true(ret >= 0);
uassert_true(recv_buf[var] == (var + 1));
}
#ifdef RT_USING_MESSAGEQUEUE_PRIORITY
rt_int32_t msg_prio;
while (testmq->entry == MAX_MSGS)
{
rt_thread_delay(100);
}
for (int var = 0; var < MAX_MSGS; ++var)
{
ret = rt_mq_recv_prio(testmq, &recv_buf[var], sizeof(recv_buf[0]), &msg_prio, RT_WAITING_FOREVER, RT_UNINTERRUPTIBLE);
rt_kprintf("msg_prio = %d\r\n", msg_prio);
uassert_true(ret >= 0);
uassert_true(recv_buf[var] == (MAX_MSGS - var));
}
#endif
}
static void mq_recv_entry(void *param)
{
mq_recv_case(&static_mq);
#ifdef RT_USING_HEAP
if(dynamic_mq != RT_NULL)
{
mq_recv_case(dynamic_mq);
}
#endif /* RT_USING_HEAP */
rt_event_send(&finish_e, MQRECV_FINIHS);
}
static void test_mq_testcase(void)
{
rt_thread_startup(&mq_send_thread);
rt_thread_startup(&mq_recv_thread);
rt_event_recv(&finish_e, MQSEND_FINISH | MQRECV_FINIHS, RT_EVENT_FLAG_AND, RT_WAITING_FOREVER, RT_NULL);
}
static void test_mq_detach(void)
{
rt_err_t ret = rt_mq_detach(&static_mq);
uassert_true(ret == RT_EOK);
}
static void test_mq_delete(void)
{
#ifdef RT_USING_HEAP
rt_err_t ret = rt_mq_delete(dynamic_mq);
uassert_true(ret == RT_EOK);
#endif /* RT_USING_HEAP */
}
static rt_err_t utest_tc_init(void)
{
rt_err_t ret ;
ret = rt_thread_init(&mq_send_thread, "mq_send", mq_send_entry, RT_NULL, mq_send_stack, sizeof(mq_send_stack), 22, 20);
if(ret != RT_EOK)
return -RT_ERROR;
ret = rt_thread_init(&mq_recv_thread, "mq_recv", mq_recv_entry, RT_NULL, mq_recv_stack, sizeof(mq_recv_stack), 23, 20);
if(ret != RT_EOK)
return -RT_ERROR;
#ifdef RT_USING_SMP
rt_thread_control(&mq_send_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
rt_thread_control(&mq_recv_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
#endif
ret = rt_event_init(&finish_e, "finish", RT_IPC_FLAG_FIFO);
if(ret != RT_EOK)
return -RT_ERROR;
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_mq_init);
UTEST_UNIT_RUN(test_mq_create);
UTEST_UNIT_RUN(test_mq_testcase);
UTEST_UNIT_RUN(test_mq_detach);
UTEST_UNIT_RUN(test_mq_delete);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.messagequeue_tc", utest_tc_init, utest_tc_cleanup, 1000);

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-12-25 Shell the first version
*/
#include <rtthread.h>
#include "utest.h"
#define TEST_LOOP_TIMES 20
static struct rt_semaphore _thr_exit_sem;
static void _thread_entry(void *param)
{
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
{
rt_kprintf("This is thread %p\n", rt_thread_self());
rt_thread_mdelay(1);
}
rt_sem_release(&_thr_exit_sem);
return;
}
#define TEST_THREAD_COUNT 16
static void mtsafe_kprint_tc(void)
{
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
{
rt_thread_t new_thread =
rt_thread_create(
"test",
_thread_entry,
NULL,
UTEST_THR_STACK_SIZE,
UTEST_THR_PRIORITY,
100);
rt_thread_startup(new_thread);
}
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
{
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
}
}
static rt_err_t utest_tc_init(void)
{
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_sem_detach(&_thr_exit_sem);
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(mtsafe_kprint_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.mtsafe_kprint", utest_tc_init, utest_tc_cleanup, 10);

Some files were not shown because too many files have changed in this diff Show More