import RT-Thread@9217865c without bsp, libcpu and components/net

This commit is contained in:
Zihao Yu 2023-05-20 16:23:33 +08:00
commit e2376a3709
1414 changed files with 390370 additions and 0 deletions

90
examples/file/listdir.c Normal file
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 */

89
examples/file/readspeed.c Normal file
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 */

170
examples/file/readwrite.c Normal file
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 */

53
examples/file/seekdir.c Normal file
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 */

100
examples/file/writespeed.c Normal file
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 */

6
examples/libc/SConscript Normal file
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')

59
examples/libc/dirent.c Normal file
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);

22
examples/libc/env.c Normal file
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);

45
examples/libc/ex1.c Normal file
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);

122
examples/libc/ex2.c Normal file
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);

162
examples/libc/ex3.c Normal file
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);
}

116
examples/libc/ex4.c Normal file
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);

113
examples/libc/ex5.c Normal file
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);

45
examples/libc/ex6.c Normal file
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_sleep
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);

109
examples/libc/ex7.c Normal file
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_sleep
/* 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);

520
examples/libc/file.c Normal file
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_sleep(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);

60
examples/libc/memory.c Normal file
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);

129
examples/libc/mq.c Normal file
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);

210
examples/libc/printf.c Normal file
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);

47
examples/libc/rand.c Normal file
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);

74
examples/libc/sem.c Normal file
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 */

27
examples/libc/time.c Normal file
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);

244
examples/network/chargen.c Normal file
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,260 @@
/*
* 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_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, close the socket.");
goto __exit;
}
else if (bytes_received == 0)
{
/* Print warning message when recv function returns 0 */
/* 打印recv函数返回值为0的警告信息 */
LOG_W("Received warning, recv function returns 0.");
continue;
}
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, close the socket.");
goto __exit;
}
else if (ret == 0)
{
/* Print warning message when send function returns 0 */
/* 打印send函数返回值为0的警告信息 */
LOG_W("Send warning, send function returns 0.");
}
}
__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,286 @@
/*
* 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_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, close the connect.");
closesocket(connected);
connected = -1;
break;
}
else if (bytes_received == 0)
{
/* Print warning message when recv function returns 0 */
/* 打印recv函数返回值为0的警告信息 */
LOG_W("Received warning, recv function returns 0.");
continue;
}
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, close the connect.");
closesocket(connected);
connected = -1;
break;
}
else if (ret == 0)
{
/* Print warning message when send function returns 0 */
/* 打印send函数返回值为0的警告信息 */
LOG_W("Send warning, send function returns 0.");
}
}
}
__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

55
examples/pm/timer_app.c Normal file
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 */

77
examples/pm/wakeup_app.c Normal file
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);

585
examples/test/avl.c Normal file
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)
{
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;
}

516
examples/test/device_test.c Normal file
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

412
examples/test/dhry.h Normal file
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;

349
examples/test/dhry_1.c Normal file
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);

192
examples/test/dhry_2.c Normal file
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 */

297
examples/test/fs_test.c Normal file
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 */

114
examples/test/mem_test.c Normal file
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

345
examples/test/net_test.c Normal file
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);

327
examples/test/rbb_test.c Normal file
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);

61
examples/test/rtc_test.c Normal file
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)

73
examples/utest/README.md Normal file
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,13 @@
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
# 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,5 @@
CONFIG_UTEST_MEMHEAP_TC=y
# dependencies
CONFIG_RT_USING_SMART=y
CONFIG_RT_USING_MEMHEAP=y

View file

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

View file

@ -0,0 +1,19 @@
menu "RT-Thread Utestcases"
config RT_USING_UTESTCASES
bool "RT-Thread Utestcases"
default n
select RT_USING_UTEST
if RT_USING_UTESTCASES
source "$RTT_DIR/examples/utest/testcases/utest/Kconfig"
source "$RTT_DIR/examples/utest/testcases/kernel/Kconfig"
source "$RTT_DIR/examples/utest/testcases/cpp11/Kconfig"
source "$RTT_DIR/examples/utest/testcases/drivers/serial_v2/Kconfig"
source "$RTT_DIR/examples/utest/testcases/posix/Kconfig"
source "$RTT_DIR/examples/utest/testcases/mm/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,7 @@
menu "Utest Serial Testcase"
config UTEST_SERIAL_TC
bool "Serial testcase"
default n
endmenu

View file

@ -0,0 +1,120 @@
## 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 | 串口接收非阻塞和发送非阻塞模式 的测试用例 |
## 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次。
## 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` 运行串口接收阻塞和发送阻塞测试用例。
如果仅仅配置了 `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,16 @@
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
''')
CPPPATH = [cwd]
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_TC'], CPPPATH = CPPPATH)
Return('group')

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,62 @@
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"
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_ATOMIC_TC
bool "atomic test"
default n
endmenu

View file

@ -0,0 +1,49 @@
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']
if GetDepend(['UTEST_MAILBOX_TC']):
src += ['mailbox_tc.c']
if GetDepend(['UTEST_THREAD_TC']):
src += ['thread_tc.c']
if GetDepend(['UTEST_ATOMIC_TC']):
src += ['atomic_tc.c']
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
Return('group')

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
* 2022-07-27 flybreak the first version
* 2023-03-21 WangShun add atomic test
*/
#include <rtthread.h>
#include "utest.h"
#include "rtatomic.h"
#include <rthw.h>
#define THREAD_PRIORITY 25
#define THREAD_TIMESLICE 1
#define THREAD_STACKSIZE 1024
/* 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;
int i;
sem_t = rt_sem_create("atomic_sem", 0, RT_IPC_FLAG_PRIO);
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);
}
uassert_true(count == 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,344 @@
/*
* 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
*/
#include <rtthread.h>
#include "utest.h"
#include <stdlib.h>
#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[1024];
static struct rt_thread thread3;
rt_align(RT_ALIGN_SIZE)
static char thread4_stack[1024];
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[1024];
static struct rt_thread thread1;
rt_align(RT_ALIGN_SIZE)
static char thread2_stack[1024];
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,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 uint32_t irq_count = 0;
static 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,371 @@
/*
* 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
*/
#include <rtthread.h>
#include "utest.h"
#include <stdlib.h>
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[1024];
static struct rt_thread thread1;
rt_align(RT_ALIGN_SIZE)
static char thread2_stack[1024];
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,
1024,
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,
1024,
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,588 @@
/*
* 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 */
#ifdef ARCH_CPU_64BIT
rt_uint32_t resv;
#endif /* ARCH_CPU_64BIT */
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,192 @@
/*
* 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
*/
#include <rtthread.h>
#include "utest.h"
#define MSG_SIZE 4
#define MAX_MSGS 5
static struct rt_messagequeue static_mq;
static rt_uint8_t mq_buf[(MSG_SIZE + (rt_uint8_t)sizeof(rt_ubase_t)) * MAX_MSGS];
static struct rt_thread mq_send_thread;
static struct rt_thread mq_recv_thread;
static rt_uint8_t mq_send_stack[1024];
static rt_uint8_t mq_recv_stack[1024];
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);
}
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_err_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 == RT_EOK);
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 == RT_EOK);
uassert_true(recv_buf[var] == (var + 1));
}
}
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;
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,676 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-09.01 luckyzjq the first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
static struct rt_mutex static_mutex;
#ifdef RT_USING_HEAP
static rt_mutex_t dynamic_mutex;
#endif /* RT_USING_HEAP */
/* init test */
static void test_static_mutex_init(void)
{
rt_err_t result = -RT_ERROR;
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
result = rt_mutex_detach(&static_mutex);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
result = rt_mutex_detach(&static_mutex);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
uassert_true(RT_TRUE);
}
/* static take test */
static void static_mutex_take_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex;
int rand_num = rand() % 0x1000;
mutex = (rt_mutex_t)param;
result = rt_mutex_take(mutex, rand_num);
if (RT_EOK == result)
{
uassert_true(RT_FALSE);
}
}
static void test_static_mutex_take(void)
{
rt_err_t result;
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* take mutex and not release */
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
rt_thread_t tid = rt_thread_create("mutex_th",
static_mutex_take_entry,
&static_mutex,
2048,
10,
10);
if (RT_NULL == tid)
{
uassert_true(RT_FALSE);
return;
}
/* startup thread take second */
rt_thread_startup(tid);
/* let system schedule */
rt_thread_mdelay(5);
result = rt_mutex_detach(&static_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
/* static release test */
static void static_mutex_release_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex;
int rand_num = rand() % 0x1000;
mutex = (rt_mutex_t)param;
result = rt_mutex_take(mutex, rand_num);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
static void test_static_mutex_release(void)
{
rt_err_t result;
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* take mutex */
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* release mutex */
result = rt_mutex_release(&static_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
rt_thread_t tid = rt_thread_create("mutex_th",
static_mutex_release_entry,
&static_mutex,
2048,
10,
10);
if (RT_NULL == tid)
{
uassert_true(RT_FALSE);
return;
}
/* startup thread and take mutex second */
rt_thread_startup(tid);
/* let system schedule */
rt_thread_mdelay(5);
result = rt_mutex_detach(&static_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
/* static trytake test */
static void static_mutex_trytake_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex;
mutex = (rt_mutex_t)param;
result = rt_mutex_trytake(mutex);
if (RT_EOK == result)
{
uassert_true(RT_FALSE);
}
}
static void test_static_mutex_trytake(void)
{
rt_err_t result;
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* take mutex and not release */
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
rt_thread_t tid = rt_thread_create("mutex_th",
static_mutex_trytake_entry,
&static_mutex,
2048,
10,
10);
if (RT_NULL == tid)
{
uassert_true(RT_FALSE);
return;
}
/* startup thread and trytake mutex second */
rt_thread_startup(tid);
/* let system schedule */
rt_thread_mdelay(5);
result = rt_mutex_detach(&static_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;
/* static mutex priority reverse test */
static void static_thread1_entry(void *param)
{
/* let system schedule */
rt_thread_mdelay(100);
/* thread3 hode mutex thread2 take mutex */
/* check thread2 and thread3 priority */
if (tid2->current_priority != tid3->current_priority)
{
uassert_true(RT_FALSE);
}
else
{
uassert_true(RT_TRUE);
}
}
static void static_thread2_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex = (rt_mutex_t)param;
/* let system schedule */
rt_thread_mdelay(50);
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
if (result == RT_EOK)
{
rt_mutex_release(mutex);
}
}
static void static_thread3_entry(void *param)
{
rt_tick_t tick;
rt_err_t result;
rt_mutex_t mutex = (rt_mutex_t)param;
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
uassert_true(RT_FALSE);
}
tick = rt_tick_get();
while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2));
rt_mutex_release(mutex);
}
static void test_static_pri_reverse(void)
{
rt_err_t result;
tid1 = RT_NULL;
tid2 = RT_NULL;
tid3 = RT_NULL;
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* thread1 */
tid1 = rt_thread_create("thread1",
static_thread1_entry,
&static_mutex,
1024,
10 - 1,
10);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
/* thread2 */
tid2 = rt_thread_create("thread2",
static_thread2_entry,
&static_mutex,
1024,
10,
10);
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
/* thread3 */
tid3 = rt_thread_create("thread3",
static_thread3_entry,
&static_mutex,
1024,
10 + 1,
10);
if (tid3 != RT_NULL)
rt_thread_startup(tid3);
rt_thread_mdelay(1000);
result = rt_mutex_detach(&static_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
/* create test */
static void test_dynamic_mutex_create(void)
{
rt_err_t result = -RT_ERROR;
/* PRIO mode */
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_mutex)
{
uassert_true(RT_FALSE);
}
result = rt_mutex_delete(dynamic_mutex);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
/* FIFO mode */
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_mutex)
{
uassert_true(RT_FALSE);
}
result = rt_mutex_delete(dynamic_mutex);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
uassert_true(RT_TRUE);
}
/* dynamic take test */
static void dynamic_mutex_take_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex;
int rand_num = rand() % 0x1000;
mutex = (rt_mutex_t)param;
result = rt_mutex_take(mutex, rand_num);
if (RT_EOK == result)
{
uassert_true(RT_FALSE);
}
}
static void test_dynamic_mutex_take(void)
{
rt_err_t result;
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_mutex)
{
uassert_true(RT_FALSE);
return;
}
/* take mutex and not release */
result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
rt_thread_t tid = rt_thread_create("mutex_th",
dynamic_mutex_take_entry,
dynamic_mutex,
2048,
10,
10);
if (RT_NULL == tid)
{
uassert_true(RT_FALSE);
return;
}
/* startup thread take second */
rt_thread_startup(tid);
/* let system schedule */
rt_thread_mdelay(5);
result = rt_mutex_delete(dynamic_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
/* dynamic release test */
static void dynamic_mutex_release_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex;
int rand_num = rand() % 0x1000;
mutex = (rt_mutex_t)param;
result = rt_mutex_take(mutex, rand_num);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
static void test_dynamic_mutex_release(void)
{
rt_err_t result;
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_mutex)
{
uassert_true(RT_FALSE);
return;
}
/* take mutex */
result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* release mutex */
result = rt_mutex_release(dynamic_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
rt_thread_t tid = rt_thread_create("mutex_th",
dynamic_mutex_release_entry,
dynamic_mutex,
2048,
10,
10);
if (RT_NULL == tid)
{
uassert_true(RT_FALSE);
return;
}
/* startup thread and take mutex second */
rt_thread_startup(tid);
/* let system schedule */
rt_thread_mdelay(5);
result = rt_mutex_delete(dynamic_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
/* dynamic trytake test */
static void dynamic_mutex_trytake_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex;
mutex = (rt_mutex_t)param;
result = rt_mutex_trytake(mutex);
if (RT_EOK == result)
{
uassert_true(RT_FALSE);
}
}
static void test_dynamic_mutex_trytake(void)
{
rt_err_t result;
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_mutex)
{
uassert_true(RT_FALSE);
return;
}
/* take mutex and not release */
result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
rt_thread_t tid = rt_thread_create("mutex_th",
dynamic_mutex_trytake_entry,
dynamic_mutex,
2048,
10,
10);
if (RT_NULL == tid)
{
uassert_true(RT_FALSE);
return;
}
/* startup thread and trytake mutex second */
rt_thread_startup(tid);
/* let system schedule */
rt_thread_mdelay(5);
result = rt_mutex_delete(dynamic_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
/* dynamic mutex priority reverse test */
static void dynamic_thread1_entry(void *param)
{
/* let system schedule */
rt_thread_mdelay(100);
/* thread3 hode mutex thread2 take mutex */
/* check thread2 and thread3 priority */
if (tid2->current_priority != tid3->current_priority)
{
uassert_true(RT_FALSE);
}
else
{
uassert_true(RT_TRUE);
}
}
static void dynamic_thread2_entry(void *param)
{
rt_err_t result;
rt_mutex_t mutex = (rt_mutex_t)param;
/* let system schedule */
rt_thread_mdelay(50);
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
if (result == RT_EOK)
{
rt_mutex_release(mutex);
}
}
static void dynamic_thread3_entry(void *param)
{
rt_tick_t tick;
rt_err_t result;
rt_mutex_t mutex = (rt_mutex_t)param;
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
uassert_true(RT_FALSE);
}
tick = rt_tick_get();
while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2));
rt_mutex_release(mutex);
}
static void test_dynamic_pri_reverse(void)
{
rt_err_t result;
tid1 = RT_NULL;
tid2 = RT_NULL;
tid3 = RT_NULL;
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_mutex)
{
uassert_true(RT_FALSE);
return;
}
/* thread1 */
tid1 = rt_thread_create("thread1",
dynamic_thread1_entry,
dynamic_mutex,
1024,
10 - 1,
10);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
/* thread2 */
tid2 = rt_thread_create("thread2",
dynamic_thread2_entry,
dynamic_mutex,
1024,
10,
10);
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
/* thread3 */
tid3 = rt_thread_create("thread3",
dynamic_thread3_entry,
dynamic_mutex,
1024,
10 + 1,
10);
if (tid3 != RT_NULL)
rt_thread_startup(tid3);
rt_thread_mdelay(1000);
result = rt_mutex_delete(dynamic_mutex);
if (RT_EOK != result)
uassert_true(RT_FALSE);
uassert_true(RT_TRUE);
}
static rt_err_t utest_tc_init(void)
{
#ifdef RT_USING_HEAP
dynamic_mutex = RT_NULL;
#endif /* RT_USING_HEAP */
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
#ifdef RT_USING_HEAP
dynamic_mutex = RT_NULL;
#endif /* RT_USING_HEAP */
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_static_mutex_init);
UTEST_UNIT_RUN(test_static_mutex_take);
UTEST_UNIT_RUN(test_static_mutex_release);
UTEST_UNIT_RUN(test_static_mutex_trytake);
UTEST_UNIT_RUN(test_static_pri_reverse);
#ifdef RT_USING_HEAP
UTEST_UNIT_RUN(test_dynamic_mutex_create);
UTEST_UNIT_RUN(test_dynamic_mutex_take);
UTEST_UNIT_RUN(test_dynamic_mutex_release);
UTEST_UNIT_RUN(test_dynamic_mutex_trytake);
UTEST_UNIT_RUN(test_dynamic_pri_reverse);
#endif
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.mutex_tc", utest_tc_init, utest_tc_cleanup, 1000);
/********************* end of file ************************/

View file

@ -0,0 +1,558 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-08-12 luckyzjq the first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
static struct rt_semaphore static_semaphore;
#ifdef RT_USING_HEAP
static rt_sem_t dynamic_semaphore;
#endif /* RT_USING_HEAP */
static void test_static_semaphore_init(void)
{
rt_err_t result;
int rand_num = rand() % 0x10000;
for (int i = 0; i < rand_num; i++)
{
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
break;
}
rt_sem_detach(&static_semaphore);
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_FIFO);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
break;
}
rt_sem_detach(&static_semaphore);
}
uassert_true(RT_TRUE);
}
static void test_static_semaphore_detach(void)
{
rt_err_t result;
int rand_num = rand() % 0x10000;
for (int i = 0; i < rand_num; i++)
{
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_PRIO);
if (RT_EOK != result)
{
break;
}
result = rt_sem_detach(&static_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
break;
}
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_FIFO);
if (RT_EOK != result)
{
break;
}
result = rt_sem_detach(&static_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
break;
}
}
uassert_true(RT_TRUE);
}
static void test_static_semaphore_take(void)
{
rt_err_t result;
result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO);
if (RT_EOK == result)
{
/* first take */
result = rt_sem_take(&static_semaphore, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* second take */
result = rt_sem_take(&static_semaphore, 100);
if (-RT_ETIMEOUT != result)
uassert_true(RT_FALSE);
}
else
{
return;
}
rt_sem_detach(&static_semaphore);
uassert_true(RT_TRUE);
return;
}
static void test_static_semaphore_trytake(void)
{
rt_err_t result;
result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO);
if (RT_EOK == result)
{
/* first take */
result = rt_sem_trytake(&static_semaphore);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* second take */
result = rt_sem_trytake(&static_semaphore);
if (-RT_ETIMEOUT != result)
uassert_true(RT_FALSE);
}
else
{
return;
}
rt_sem_detach(&static_semaphore);
uassert_true(RT_TRUE);
return;
}
static void test_static_semaphore_release(void)
{
rt_err_t result;
result = rt_sem_init(&static_semaphore, "static_sem", 0, RT_IPC_FLAG_PRIO);
if (RT_EOK == result)
{
/* first take */
result = rt_sem_take(&static_semaphore, 100);
if (-RT_ETIMEOUT != result)
uassert_true(RT_FALSE);
/* release */
result = rt_sem_release(&static_semaphore);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* second take */
result = rt_sem_take(&static_semaphore, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
}
else
{
return;
}
rt_sem_detach(&static_semaphore);
uassert_true(RT_TRUE);
return;
}
static void test_static_semaphore_control(void)
{
rt_err_t result;
int value = 0;
value = rand() % 100;
result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO);
if (RT_EOK == result)
{
result = rt_sem_control(&static_semaphore, RT_IPC_CMD_RESET, &value);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
else
{
return;
}
for (int i = 0; i < value; i++)
{
result = rt_sem_take(&static_semaphore, 10);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
rt_sem_detach(&static_semaphore);
uassert_true(RT_TRUE);
}
static void static_release_isr_hardware_callback(void *param)
{
rt_err_t result;
result = rt_sem_release(&static_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
static void static_release_isr_software_callback(void *param)
{
rt_err_t result;
result = rt_sem_release(&static_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
static void test_static_semaphore_release_isr(void)
{
rt_err_t result;
rt_timer_t hardware_timer;
rt_timer_t software_timer;
/* create timer */
hardware_timer = rt_timer_create("release_isr",
static_release_isr_hardware_callback,
RT_NULL,
100,
RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_ONE_SHOT);
software_timer = rt_timer_create("release_isr",
static_release_isr_software_callback,
RT_NULL,
100,
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
/* start tiemr */
if (hardware_timer)
rt_timer_start(hardware_timer);
if (software_timer)
rt_timer_start(software_timer);
result = rt_sem_init(&static_semaphore, "static_sem", 0, RT_IPC_FLAG_PRIO);
if (RT_EOK == result)
{
for (int i = 0; i < 2; i++)
{
result = rt_sem_take(&static_semaphore, 1000);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
}
else
{
return;
}
rt_sem_detach(&static_semaphore);
rt_timer_delete(hardware_timer);
rt_timer_delete(software_timer);
uassert_true(RT_TRUE);
}
#ifdef RT_USING_HEAP
static void test_dynamic_semaphore_create(void)
{
int rand_num = rand() % 0x10000;
for (int i = 0; i < rand_num; i++)
{
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_semaphore)
{
uassert_true(RT_FALSE);
break;
}
rt_sem_delete(dynamic_semaphore);
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_FIFO);
if (RT_NULL == dynamic_semaphore)
{
uassert_true(RT_FALSE);
break;
}
rt_sem_delete(dynamic_semaphore);
}
uassert_true(RT_TRUE);
}
static void test_dynamic_semaphore_delete(void)
{
rt_err_t result;
int rand_num = rand() % 0x10000;
for (int i = 0; i < rand_num; i++)
{
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_PRIO);
if (RT_NULL == dynamic_semaphore)
{
break;
}
result = rt_sem_delete(dynamic_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
break;
}
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_FIFO);
if (RT_NULL == dynamic_semaphore)
{
break;
}
result = rt_sem_delete(dynamic_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
break;
}
}
uassert_true(RT_TRUE);
}
static void test_dynamic_semaphore_take(void)
{
rt_err_t result;
dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO);
if (RT_NULL != dynamic_semaphore)
{
/* first take */
result = rt_sem_take(dynamic_semaphore, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* second take */
result = rt_sem_take(dynamic_semaphore, 100);
if (-RT_ETIMEOUT != result)
uassert_true(RT_FALSE);
}
else
{
return;
}
rt_sem_delete(dynamic_semaphore);
uassert_true(RT_TRUE);
return;
}
static void test_dynamic_semaphore_trytake(void)
{
rt_err_t result;
dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO);
if (RT_NULL != dynamic_semaphore)
{
/* first take */
result = rt_sem_trytake(dynamic_semaphore);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* second take */
result = rt_sem_trytake(dynamic_semaphore);
if (-RT_ETIMEOUT != result)
uassert_true(RT_FALSE);
}
else
{
return;
}
rt_sem_delete(dynamic_semaphore);
uassert_true(RT_TRUE);
return;
}
static void test_dynamic_semaphore_release(void)
{
rt_err_t result;
dynamic_semaphore = rt_sem_create("static_sem", 0, RT_IPC_FLAG_PRIO);
if (RT_NULL != dynamic_semaphore)
{
/* first take */
result = rt_sem_take(dynamic_semaphore, 100);
if (-RT_ETIMEOUT != result)
uassert_true(RT_FALSE);
/* release */
result = rt_sem_release(dynamic_semaphore);
if (RT_EOK != result)
uassert_true(RT_FALSE);
/* second take */
result = rt_sem_take(dynamic_semaphore, RT_WAITING_FOREVER);
if (RT_EOK != result)
uassert_true(RT_FALSE);
}
else
{
return;
}
rt_sem_delete(dynamic_semaphore);
uassert_true(RT_TRUE);
return;
}
static void test_dynamic_semaphore_control(void)
{
rt_err_t result;
int value = 0;
value = rand() % 100;
dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO);
if (RT_NULL != dynamic_semaphore)
{
result = rt_sem_control(dynamic_semaphore, RT_IPC_CMD_RESET, &value);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
else
{
return;
}
for (int i = 0; i < value; i++)
{
result = rt_sem_take(dynamic_semaphore, 10);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
rt_sem_delete(dynamic_semaphore);
uassert_true(RT_TRUE);
}
static void dynamic_release_isr_hardware_callback(void *param)
{
rt_err_t result;
result = rt_sem_release(dynamic_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
static void dynamic_release_isr_software_callback(void *param)
{
rt_err_t result;
result = rt_sem_release(dynamic_semaphore);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
static void test_dynamic_semaphore_release_isr(void)
{
rt_err_t result;
rt_timer_t hardware_timer;
rt_timer_t software_timer;
/* create timer */
hardware_timer = rt_timer_create("release_isr",
dynamic_release_isr_hardware_callback,
RT_NULL,
100,
RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_ONE_SHOT);
software_timer = rt_timer_create("release_isr",
dynamic_release_isr_software_callback,
RT_NULL,
100,
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
/* start tiemr */
if (hardware_timer)
rt_timer_start(hardware_timer);
if (software_timer)
rt_timer_start(software_timer);
dynamic_semaphore = rt_sem_create("static_sem", 0, RT_IPC_FLAG_PRIO);
if (RT_NULL != dynamic_semaphore)
{
for (int i = 0; i < 2; i++)
{
result = rt_sem_take(dynamic_semaphore, 1000);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
}
}
else
{
return;
}
rt_sem_delete(dynamic_semaphore);
rt_timer_delete(hardware_timer);
rt_timer_delete(software_timer);
uassert_true(RT_TRUE);
}
#endif /* RT_USING_HEAP */
static rt_err_t utest_tc_init(void)
{
#ifdef RT_USING_HEAP
dynamic_semaphore = RT_NULL;
#endif /* RT_USING_HEAP */
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
#ifdef RT_USING_HEAP
dynamic_semaphore = RT_NULL;
#endif /* RT_USING_HEAP */
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_static_semaphore_init);
UTEST_UNIT_RUN(test_static_semaphore_take);
UTEST_UNIT_RUN(test_static_semaphore_release);
UTEST_UNIT_RUN(test_static_semaphore_detach);
UTEST_UNIT_RUN(test_static_semaphore_trytake);
UTEST_UNIT_RUN(test_static_semaphore_control);
UTEST_UNIT_RUN(test_static_semaphore_release_isr);
#ifdef RT_USING_HEAP
UTEST_UNIT_RUN(test_dynamic_semaphore_create);
UTEST_UNIT_RUN(test_dynamic_semaphore_take);
UTEST_UNIT_RUN(test_dynamic_semaphore_release);
UTEST_UNIT_RUN(test_dynamic_semaphore_delete);
UTEST_UNIT_RUN(test_dynamic_semaphore_trytake);
UTEST_UNIT_RUN(test_dynamic_semaphore_control);
UTEST_UNIT_RUN(test_dynamic_semaphore_release_isr);
#endif /* RT_USING_HEAP */
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.semaphore_tc", utest_tc_init, utest_tc_cleanup, 1000);

View file

@ -0,0 +1,199 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-08-12 flybreak the first version
*
* case 1:rt_signal_install, install all available signal
* case 2:rt_signal_install, install illegal signal
* case 3:rt_signal_mask/unmask, one thread self, install and unmask, then kill, should received.
* case 4:rt_signal_mask/unmask, one thread self, install and unmask and mask, then kill, should can't received.
* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received.
* case 6:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: sleep 2s then kill, should can't received.
* case 7:rt_signal_kill, kill legal thread, return 0;
* case 8:rt_signal_kill, kill illegal thread, return failed (unused);
* case 9:rt_signal_kill, kill illegal signo, return -RT_EINVAL;
*
*/
#include <rtthread.h>
#include "utest.h"
int recive_sig = 0;
void sig_handle_default(int signo)
{
recive_sig = signo;
}
static void rt_signal_install_test(void)
{
int signo;
rt_sighandler_t result;
/* case 1:rt_signal_install, install all available signal. */
for (signo = 0; signo < RT_SIG_MAX; signo++)
{
result = rt_signal_install(signo, sig_handle_default);
uassert_true(result != SIG_ERR);
}
/* case 2:rt_signal_install, install illegal signal. */
result = rt_signal_install(signo, sig_handle_default);
uassert_true(result == SIG_ERR);
return;
}
static void rt_signal_mask_test(void)
{
int signo;
rt_sighandler_t result;
/* case 3:rt_signal_mask/unmask, one thread self, install and unmask, then kill, should received. */
for (signo = 0; signo < RT_SIG_MAX; signo++)
{
recive_sig = -1;
result = rt_signal_install(signo, sig_handle_default);
uassert_true(result != SIG_ERR);
rt_signal_unmask(signo);
uassert_int_equal(rt_thread_kill(rt_thread_self(), signo), RT_EOK);
rt_thread_mdelay(1);
uassert_int_equal(recive_sig, signo);
}
return;
}
static void rt_signal_unmask_test(void)
{
int signo;
rt_sighandler_t result;
/* case 4:rt_signal_mask/unmask, one thread self, install and unmask and mask, then kill, should can't received. */
for (signo = 0; signo < RT_SIG_MAX; signo++)
{
recive_sig = -1;
result = rt_signal_install(signo, sig_handle_default);
uassert_true(result != SIG_ERR);
rt_signal_unmask(signo);
rt_signal_mask(signo);
uassert_int_equal(rt_thread_kill(rt_thread_self(), signo), RT_EOK);
rt_thread_mdelay(1);
uassert_int_not_equal(recive_sig, signo);
}
return;
}
static void rt_signal_kill_test(void)
{
int signo;
rt_sighandler_t result;
/* case 7:rt_signal_kill, kill legal thread, return 0; */
for (signo = 0; signo < RT_SIG_MAX; signo++)
{
recive_sig = -1;
result = rt_signal_install(signo, sig_handle_default);
uassert_true(result != SIG_ERR);
rt_signal_unmask(signo);
uassert_int_equal(rt_thread_kill(rt_thread_self(), signo), RT_EOK);
rt_thread_mdelay(1);
uassert_int_equal(recive_sig, signo);
}
/* case 8:rt_signal_kill, kill illegal thread, return failed; */
// uassert_true(rt_thread_kill((rt_thread_t)-1, signo) == -RT_ERROR);
/* case 9:rt_signal_kill, kill illegal signo, return -RT_EINVAL; */
uassert_true(rt_thread_kill(rt_thread_self(), -1) == -RT_EINVAL);
return;
}
void rt_signal_wait_thread(void *parm)
{
sigset_t selectset;
siginfo_t recive_si;
rt_signal_install(SIGUSR1, sig_handle_default);
rt_signal_unmask(SIGUSR1);
(void)sigemptyset(&selectset);
(void)sigaddset(&selectset, SIGUSR1);
/* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received. */
if (rt_signal_wait(&selectset, &recive_si, RT_TICK_PER_SECOND) != RT_EOK)
{
return;
}
recive_sig = recive_si.si_signo;
}
static void rt_signal_wait_test(void)
{
rt_thread_t t1;
recive_sig = -1;
t1 = rt_thread_create("sig_t1", rt_signal_wait_thread, 0, 4096, 14, 10);
if (t1)
{
rt_thread_startup(t1);
}
rt_thread_mdelay(1);
/* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received. */
uassert_int_equal(rt_thread_kill(t1, SIGUSR1), RT_EOK);
rt_thread_mdelay(1);
uassert_int_equal(recive_sig, SIGUSR1);
return;
}
static void rt_signal_wait_test2(void)
{
rt_thread_t t1;
recive_sig = -1;
t1 = rt_thread_create("sig_t1", rt_signal_wait_thread, 0, 4096, 14, 10);
if (t1)
{
rt_thread_startup(t1);
}
/* case 6:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: sleep 2s then kill, should can't received. */
rt_thread_mdelay(2000);
uassert_int_equal(rt_thread_kill(t1, SIGUSR1), RT_EOK);
rt_thread_mdelay(1);
uassert_int_not_equal(recive_sig, SIGUSR1);
return;
}
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)
{
#ifdef RT_USING_HEAP
UTEST_UNIT_RUN(rt_signal_install_test);
UTEST_UNIT_RUN(rt_signal_mask_test);
UTEST_UNIT_RUN(rt_signal_unmask_test);
UTEST_UNIT_RUN(rt_signal_kill_test);
UTEST_UNIT_RUN(rt_signal_wait_test);
UTEST_UNIT_RUN(rt_signal_wait_test2);
#endif /* RT_USING_HEAP */
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.signal_tc", utest_tc_init, utest_tc_cleanup, 1000);
/*********************** end of file ****************************/

View file

@ -0,0 +1,323 @@
/*
* Copyright (c) 2006-2019, 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"
#define TEST_SLAB_SIZE 1024 * 1024
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 slab_alloc_context
{
rt_list_t node;
rt_size_t size;
rt_uint8_t magic;
};
struct slab_alloc_head
{
rt_list_t list;
rt_size_t count;
rt_tick_t start;
rt_tick_t end;
rt_tick_t interval;
};
#define SLAB_RANG_ALLOC_BLK_MIN 2
#define SLAB_RANG_ALLOC_BLK_MAX 5
#define SLAB_RANG_ALLOC_TEST_TIME 5
static void slab_alloc_test(void)
{
struct slab_alloc_head head;
rt_uint8_t *buf;
rt_slab_t heap;
rt_size_t size;
struct slab_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(SLAB_RANG_ALLOC_TEST_TIME * 1000);
head.interval = (head.end - head.start) / 20;
buf = rt_malloc(TEST_SLAB_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_SLAB_SIZE);
heap = rt_slab_init("slab_tc", buf, TEST_SLAB_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("#");
}
// %60 probability to perform alloc operation
if (rand() % 10 >= 4)
{
size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN;
size *= sizeof(struct slab_alloc_context);
ctx = rt_slab_alloc(heap, 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 slab_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_slab_free(heap, 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 slab_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_slab_free(heap, ctx);
head.count --;
}
}
}
while (!rt_list_isempty(&head.list))
{
ctx = rt_list_first_entry(&head.list, struct slab_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_slab_free(heap, ctx);
head.count --;
}
uassert_int_equal(head.count, 0);
// slab heap deinit
rt_slab_detach(heap);
/* release test resources */
rt_free(buf);
}
#define SLAB_RANG_REALLOC_BLK_MIN 0
#define SLAB_RANG_REALLOC_BLK_MAX 5
#define SLAB_RANG_REALLOC_TEST_TIME 5
struct slab_realloc_context
{
rt_size_t size;
rt_uint8_t magic;
};
struct slab_realloc_head
{
struct slab_realloc_context **ctx_tab;
rt_size_t count;
rt_tick_t start;
rt_tick_t end;
rt_tick_t interval;
};
static void slab_realloc_test(void)
{
struct slab_realloc_head head;
rt_uint8_t *buf;
rt_slab_t heap;
rt_size_t size, idx;
struct slab_realloc_context *ctx;
int res;
size = RT_ALIGN(sizeof(struct slab_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
size = TEST_SLAB_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(SLAB_RANG_ALLOC_TEST_TIME * 1000);
head.interval = (head.end - head.start) / 20;
buf = rt_malloc(TEST_SLAB_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_SLAB_SIZE);
heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE);
/* init ctx tab */
size = head.count * sizeof(struct slab_realloc_context *);
head.ctx_tab = rt_slab_alloc(heap, 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() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN;
size *= sizeof(struct slab_realloc_context);
idx = rand() % head.count;
ctx = rt_slab_realloc(heap, 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_slab_realloc(heap, ctx, 0);
head.ctx_tab[idx] = RT_NULL;
}
}
}
continue;
}
/* check slab */
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 slab */
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 slab
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_slab_realloc(heap, ctx, 0);
head.ctx_tab[idx] = RT_NULL;
}
// slab heap deinit
rt_slab_detach(heap);
/* 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(slab_alloc_test);
UTEST_UNIT_RUN(slab_realloc_test);
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.slab_tc", utest_tc_init, utest_tc_cleanup, 20);

View file

@ -0,0 +1,743 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-09.01 yangjie the firet version
* 2021-10.11 mazhiyuan add idle, yield, suspend, control, priority, delay_until
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 10
rt_align(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
#ifdef RT_USING_HEAP
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;
static rt_thread_t tid4 = RT_NULL;
static rt_thread_t tid5 = RT_NULL;
static rt_thread_t tid6 = RT_NULL;
static rt_thread_t tid7 = RT_NULL;
#endif /* RT_USING_HEAP */
static volatile rt_uint32_t tid3_delay_pass_flag = 0;
static volatile rt_uint32_t tid3_finish_flag = 0;
static volatile rt_uint32_t tid4_finish_flag = 0;
static volatile rt_uint32_t tid6_finish_flag = 0;
static rt_uint32_t thread5_source = 0;
#ifndef RT_USING_SMP
static rt_uint32_t thread_yield_flag = 0;
#endif
static rt_uint32_t entry_idle_hook_times = 0;
static rt_thread_t __current_thread;
static rt_uint8_t change_priority;
static rt_uint32_t count = 0;
void thread1_entry(void *param)
{
while (1);
}
static void test_dynamic_thread(void)
{
rt_err_t ret_startup = -RT_ERROR;
rt_err_t ret_delete = -RT_ERROR;
tid1 = rt_thread_create("thread1",
thread1_entry,
(void *)1,
THREAD_STACK_SIZE,
__current_thread->current_priority + 1,
THREAD_TIMESLICE - 5);
if (tid1 == RT_NULL)
{
uassert_false(tid1 == RT_NULL);
goto __exit;
}
ret_startup = rt_thread_startup(tid1);
if (ret_startup != RT_EOK)
{
uassert_false(ret_startup != RT_EOK);
goto __exit;
}
ret_delete = rt_thread_delete(tid1);
if (ret_delete != RT_EOK)
{
uassert_false(ret_delete != RT_EOK);
goto __exit;
}
uassert_true(tid1 != RT_NULL && ret_startup == RT_EOK && ret_delete == RT_EOK);
__exit:
if (tid1 != RT_NULL && ret_delete != RT_EOK)
{
rt_thread_delete(tid1);
}
return;
}
void thread2_entry(void *param)
{
while (1);
}
static void test_static_thread(void)
{
rt_err_t ret_init = -RT_ERROR;
rt_err_t ret_startup = -RT_ERROR;
rt_err_t ret_detach = -RT_ERROR;
ret_init = rt_thread_init(&thread2,
"thread2",
thread2_entry,
(void *)2,
&thread2_stack[0],
sizeof(thread2_stack),
__current_thread->current_priority + 1,
THREAD_TIMESLICE);
if (ret_init != RT_EOK)
{
uassert_false(ret_init != RT_EOK);
goto __exit;
}
ret_startup = rt_thread_startup(&thread2);
if (ret_startup != RT_EOK)
{
uassert_false(ret_startup != RT_EOK);
goto __exit;
}
ret_detach = rt_thread_detach(&thread2);
if (ret_detach != RT_EOK)
{
uassert_false(ret_detach != RT_EOK);
goto __exit;
}
uassert_true(ret_init == RT_EOK && ret_startup == RT_EOK && ret_detach == RT_EOK);
__exit:
if (ret_init == RT_EOK && ret_detach != RT_EOK)
{
rt_thread_detach(&thread2);
}
return;
}
static void thread3_entry(void *parameter)
{
rt_tick_t tick;
tick = rt_tick_get();
rt_thread_delay(15);
if (rt_tick_get() - tick > 16)
{
tid3_finish_flag = 1;
tid3_delay_pass_flag = 0;
return;
}
tid3_delay_pass_flag = 1;
tid3_finish_flag = 1;
}
static void test_thread_delay(void)
{
rt_err_t ret_startup = -RT_ERROR;
tid3 = rt_thread_create("thread3",
thread3_entry,
RT_NULL,
THREAD_STACK_SIZE,
__current_thread->current_priority - 1,
THREAD_TIMESLICE);
if (tid3 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid3 == RT_NULL);
goto __exit;
}
ret_startup = rt_thread_startup(tid3);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
goto __exit;
}
while (tid3_finish_flag != 1);
uassert_true(tid3_delay_pass_flag == 1);
__exit:
return;
}
static void idle_hook(void)
{
entry_idle_hook_times ++;
}
static void thread4_entry(void *parameter)
{
rt_uint32_t delay_times = 5;
while (delay_times --)
{
rt_thread_mdelay(300);
}
rt_thread_idle_delhook(idle_hook);
tid4_finish_flag = 1;
}
static void test_idle_hook(void)
{
rt_err_t ret_startup = -RT_ERROR;
rt_thread_idle_sethook(idle_hook);
tid4 = rt_thread_create("thread4",
thread4_entry,
RT_NULL,
THREAD_STACK_SIZE,
__current_thread->current_priority - 1,
THREAD_TIMESLICE);
if (tid4 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid4 == RT_NULL);
goto __exit;
}
ret_startup = rt_thread_startup(tid4);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
goto __exit;
}
while (tid4_finish_flag != 1)
{
rt_thread_mdelay(200);
}
uassert_true(entry_idle_hook_times > 0);
__exit:
return;
}
static void thread5_entry(void *parameter)
{
while (1)
{
thread5_source ++;
rt_thread_delay(5);
if (thread5_source == 5)
{
rt_thread_yield();
}
}
}
static void thread6_entry(void *parameter)
{
while (++ thread5_source <= 9);
tid6_finish_flag = 1;
}
static void test_thread_yield(void)
{
rt_err_t ret_startup = -RT_ERROR;
thread5_source = 0;
tid5 = rt_thread_create("thread5",
thread5_entry,
RT_NULL,
THREAD_STACK_SIZE,
__current_thread->current_priority - 1,
THREAD_TIMESLICE);
if (tid5 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid5 == RT_NULL);
goto __exit;
}
ret_startup = rt_thread_startup(tid5);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
goto __exit;
}
tid6 = rt_thread_create("thread6",
thread6_entry,
RT_NULL,
THREAD_STACK_SIZE,
__current_thread->current_priority - 1,
THREAD_TIMESLICE);
if (tid6 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid6 == RT_NULL);
goto __exit;
}
ret_startup = rt_thread_startup(tid6);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
goto __exit;
}
while (tid6_finish_flag != 1);
uassert_true(thread5_source == 10);
__exit:
if (tid5 != RT_NULL)
{
rt_thread_delete(tid5);
}
return;
}
static void thread7_entry(void *parameter)
{
while (1);
}
static void test_thread_control(void)
{
rt_err_t ret_control = -RT_ERROR;
rt_err_t rst_delete = -RT_ERROR;
tid7 = rt_thread_create("thread7",
thread7_entry,
RT_NULL,
THREAD_STACK_SIZE,
__current_thread->current_priority + 1,
THREAD_TIMESLICE);
if (tid7 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid7 == RT_NULL);
goto __exit;
}
ret_control = rt_thread_control(tid7, RT_THREAD_CTRL_STARTUP, RT_NULL);
if (ret_control != RT_EOK)
{
LOG_E("rt_thread_control failed!");
uassert_false(1);
goto __exit;
}
rt_thread_mdelay(200);
rt_thread_control(tid7, RT_THREAD_CTRL_CHANGE_PRIORITY, &change_priority);
if (tid7->current_priority != change_priority)
{
LOG_E("rt_thread_control failed!");
uassert_false(1);
goto __exit;
}
rst_delete = rt_thread_control(tid7, RT_THREAD_CTRL_CLOSE, RT_NULL);
if (rst_delete != RT_EOK)
{
LOG_E("rt_thread_control failed!");
uassert_false(rst_delete != RT_EOK);
goto __exit;
}
uassert_true(1);
__exit:
if (tid7 != RT_NULL && rst_delete != RT_EOK)
{
rt_thread_delete(tid7);
}
return;
}
static void thread8_entry(void *parameter)
{
for (; count < 10; count ++);
}
static void test_thread_priority(void)
{
rt_err_t ret_startup = -RT_ERROR;
rt_thread_t tid8 = RT_NULL;
tid8 = rt_thread_create("thread8",
thread8_entry,
RT_NULL,
THREAD_STACK_SIZE,
__current_thread->current_priority - 1,
THREAD_TIMESLICE);
if (tid8 == RT_NULL)
{
LOG_E("rt_thread_create failed!");
uassert_false(tid8 == RT_NULL);
return;
}
count = 0;
ret_startup = rt_thread_startup(tid8);
if (ret_startup != RT_EOK)
{
uassert_false(ret_startup != RT_EOK);
return ;
}
uassert_true(count == 10);
return;
}
static void test_delay_until(void)
{
rt_tick_t tick;
rt_tick_t check_tick = 0;
rt_tick_t delta = 0;
tick = rt_tick_get();
check_tick = tick;
rt_thread_delay_until(&tick, 100);
delta = rt_tick_get() - check_tick;
rt_kprintf("delta[100] -> %d\n", delta);
uassert_int_equal(delta, 100);
check_tick = tick;
rt_thread_delay(2);
rt_thread_delay_until(&tick, 200);
delta = rt_tick_get() - check_tick;
rt_kprintf("delta[200] -> %d\n", delta);
uassert_int_equal(delta, 200);
check_tick = tick;
rt_thread_delay(2);
rt_thread_delay_until(&tick, 300);
delta = rt_tick_get() - check_tick;
rt_kprintf("delta[300] -> %d\n", delta);
uassert_int_equal(delta, 300);
check_tick = tick;
rt_thread_delay(2);
rt_thread_delay_until(&tick, 100);
delta = rt_tick_get() - check_tick;
uassert_int_equal(delta, 100);
check_tick = tick;
rt_thread_delay(2);
rt_thread_delay_until(&tick, 50);
delta = rt_tick_get() - check_tick;
rt_kprintf("delta[50] -> %d\n", delta);
uassert_int_equal(delta, 50);
check_tick = tick;
rt_thread_delay(2);
rt_thread_delay_until(&tick, 20);
delta = rt_tick_get() - check_tick;
rt_kprintf("delta[20] -> %d\n", delta);
uassert_int_equal(delta, 20);
check_tick = tick;
rt_thread_delay(2);
rt_thread_delay_until(&tick, 10);
delta = rt_tick_get() - check_tick;
rt_kprintf("delta[10] -> %d\n", delta);
uassert_int_equal(delta, 10);
}
static rt_thread_t tidA, tidB1, tidB2;
static uint32_t timeslice_cntA, timeslice_cntB1, timeslice_cntB2;
static void test_timeslice_threadA_entry(void *parameter)
{
while (1)
{
rt_thread_delay(2);
timeslice_cntA++;
if (timeslice_cntA > 10) return;
}
}
static void test_timeslice_threadB1_entry(void *parameter)
{
while (1)
{
timeslice_cntB1++;
if (timeslice_cntA > 10) return;
}
}
static void test_timeslice_threadB2_entry(void *parameter)
{
while (1)
{
timeslice_cntB2++;
if (timeslice_cntA > 10) return;
}
}
void test_timeslice(void)
{
rt_err_t ret_startup = -RT_ERROR;
uint32_t diff;
timeslice_cntA = 0;
timeslice_cntB1 = 0;
timeslice_cntB2 = 0;
tidA = rt_thread_create("timeslice", test_timeslice_threadA_entry, RT_NULL,
2048, __current_thread->current_priority + 1, 10);
if (!tidA)
{
LOG_E("rt_thread_create failed!");
return;
}
rt_thread_control(tidA, RT_THREAD_CTRL_BIND_CPU, (void *)1);
ret_startup = rt_thread_startup(tidA);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
return ;
}
tidB1 = rt_thread_create("timeslice", test_timeslice_threadB1_entry, RT_NULL,
2048, __current_thread->current_priority + 2, 2);
if (!tidB1)
{
LOG_E("rt_thread_create failed!");
return;
}
rt_thread_control(tidB1, RT_THREAD_CTRL_BIND_CPU, (void *)1);
ret_startup = rt_thread_startup(tidB1);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
return ;
}
tidB2 = rt_thread_create("timeslice", test_timeslice_threadB2_entry, RT_NULL,
2048, __current_thread->current_priority + 2, 2);
if (!tidB2)
{
LOG_E("rt_thread_create failed!");
return;
}
rt_thread_control(tidB2, RT_THREAD_CTRL_BIND_CPU, (void *)1);
ret_startup = rt_thread_startup(tidB2);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
return ;
}
do{
rt_thread_delay(2 * 20);
}while(timeslice_cntA <= 10);
rt_kprintf("A:%d,B1:%d,B2:%d\n", timeslice_cntA, timeslice_cntB1, timeslice_cntB2);
diff = abs(timeslice_cntB1 - timeslice_cntB2);
uassert_true(diff * 100 / timeslice_cntB1 < 30);
uassert_true(timeslice_cntA == 11);
}
#ifndef RT_USING_SMP
static volatile rt_uint32_t yield_count;
static void test_thread_yield_inc_entry(void *parameter)
{
rt_uint32_t loop = 0;
while (1)
{
if (loop++ > 10001)
break;
yield_count++;
rt_thread_yield();
}
}
static void test_thread_yield_entry(void *parameter)
{
rt_err_t ret_startup = -RT_ERROR;
rt_thread_t tid;
rt_uint32_t loop = 0;
rt_uint32_t count_before;
tid = rt_thread_create("inc", test_thread_yield_inc_entry, RT_NULL,
2048, 1, 10);
if (!tid)
{
LOG_E("rt_thread_create failed!");
return;
}
ret_startup = rt_thread_startup(tid);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
return ;
}
while (1)
{
if (loop++ > 10000)
break;
count_before = yield_count;
rt_thread_yield();
if (yield_count == count_before)
{
LOG_E("yield error!");
return;
}
}
thread_yield_flag = 1;
}
void test_thread_yield_nosmp(void)
{
rt_err_t ret_startup = -RT_ERROR;
rt_thread_t tid;
yield_count = 0;
tid = rt_thread_create("chkcnt", test_thread_yield_entry, RT_NULL,
2048, 1, 10);
if (!tid)
{
LOG_E("rt_thread_create failed!");
return;
}
ret_startup = rt_thread_startup(tid);
if (ret_startup != RT_EOK)
{
LOG_E("rt_thread_startup failed!");
uassert_false(1);
return ;
}
uassert_true(thread_yield_flag == 1);
}
// static rt_uint32_t thread9_count = 0;
// static void thread9_entry(void *parameter)
// {
// while (1)
// {
// thread9_count ++;
// }
// }
// static void test_thread_suspend(void)
// {
// static rt_thread_t tid;
// rt_err_t ret_startup = -RT_ERROR;
// uint32_t count_before_suspend, count_before_resume, count_after_resume;
// tid = rt_thread_create("thread9",
// thread9_entry,
// RT_NULL,
// THREAD_STACK_SIZE,
// __current_thread->current_priority + 1,
// THREAD_TIMESLICE);
// if (tid == RT_NULL)
// {
// LOG_E("rt_thread_create failed!");
// uassert_false(tid4 == RT_NULL);
// goto __exit;
// }
// ret_startup = rt_thread_startup(tid);
// if (ret_startup != RT_EOK)
// {
// LOG_E("rt_thread_startup failed!");
// uassert_false(1);
// goto __exit;
// }
// rt_thread_delay(5);
// rt_thread_suspend(tid);
// count_before_suspend = thread9_count;
// uassert_true(count_before_suspend != 0);
// rt_thread_delay(5);
// count_before_resume = thread9_count;
// uassert_true(count_before_suspend == count_before_resume);
// rt_thread_resume(tid);
// rt_thread_delay(5);
// count_after_resume = thread9_count;
// uassert_true(count_after_resume != count_before_resume);
// __exit:
// if (tid != RT_NULL)
// {
// rt_thread_delete(tid);
// }
// return;
// }
#endif
static rt_err_t utest_tc_init(void)
{
__current_thread = rt_thread_self();
change_priority = __current_thread->current_priority + 5;
tid3_delay_pass_flag = 0;
tid3_finish_flag = 0;
tid4_finish_flag = 0;
tid6_finish_flag = 0;
entry_idle_hook_times = 0;
count = 0;
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
static void testcase(void)
{
/* init, detach */
UTEST_UNIT_RUN(test_static_thread);
/* create, delete */
UTEST_UNIT_RUN(test_dynamic_thread);
/* delay */
UTEST_UNIT_RUN(test_thread_delay);
/* idle_sethook, idle_delhook */
UTEST_UNIT_RUN(test_idle_hook);
/* yield */
UTEST_UNIT_RUN(test_thread_yield);
#ifndef RT_USING_SMP
/* yield_nosmp */
UTEST_UNIT_RUN(test_thread_yield_nosmp);
/* suspend, resume */
// UTEST_UNIT_RUN(test_thread_suspend);
#endif
/* control */
UTEST_UNIT_RUN(test_thread_control);
UTEST_UNIT_RUN(test_thread_priority);
/* delay_until */
UTEST_UNIT_RUN(test_delay_until);
/* timeslice */
// UTEST_UNIT_RUN(test_timeslice); /* Can not running in Github Action QEMU */
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.thread_tc", utest_tc_init, utest_tc_cleanup, 1000);
/********************* end of file ************************/

View file

@ -0,0 +1,520 @@
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-08-12 luckyzjq the first version
*/
#include <rtthread.h>
#include <stdlib.h>
#include "utest.h"
static rt_uint8_t timer_flag_oneshot[] = {
RT_TIMER_FLAG_ONE_SHOT,
RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER,
};
static rt_uint8_t timer_flag_periodic[] = {
RT_TIMER_FLAG_PERIODIC,
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_HARD_TIMER,
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER,
};
typedef struct test_timer_struct
{
struct rt_timer static_timer; /* static timer handler */
rt_timer_t dynamic_timer; /* dynamic timer pointer */
rt_tick_t expect_tick; /* expect tick */
rt_uint8_t test_flag; /* timer callback done flag */
} timer_struct;
static timer_struct timer;
#define test_static_timer_start test_static_timer_init
#define test_static_timer_stop test_static_timer_init
#define test_static_timer_detach test_static_timer_init
static void static_timer_oneshot(void *param)
{
timer_struct *timer_call;
timer_call = (timer_struct *)param;
timer_call->test_flag = RT_TRUE;
/* check expect tick */
if (rt_tick_get() - timer_call->expect_tick > 1)
{
uassert_true(RT_FALSE);
}
return;
}
static void static_timer_periodic(void *param)
{
rt_err_t result;
timer_struct *timer_call;
timer_call = (timer_struct *)param;
timer_call->test_flag = RT_TRUE;
/* check expect tick */
if (rt_tick_get() - timer_call->expect_tick > 1)
{
uassert_true(RT_FALSE);
}
/* periodic timer can stop */
result = rt_timer_stop(&timer_call->static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
return;
}
static void test_static_timer_init(void)
{
rt_err_t result;
int rand_num = rand() % 10;
/* one shot timer test */
for (int time_out = 0; time_out < rand_num; time_out++)
{
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
{
rt_timer_init(&timer.static_timer,
"static_timer",
static_timer_oneshot,
&timer,
time_out,
timer_flag_oneshot[i]);
/* calc expect tick */
timer.expect_tick = rt_tick_get() + time_out;
/* start timer */
result = rt_timer_start(&timer.static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* wait for timerout */
rt_thread_delay(time_out + 1);
/* detach timer */
result = rt_timer_detach(&timer.static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
if (timer.test_flag != RT_TRUE)
{
uassert_true(RT_FALSE);
return;
}
}
}
/* periodic timer test */
for (int time_out = 0; time_out < rand_num; time_out++)
{
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
{
rt_timer_init(&timer.static_timer,
"static_timer",
static_timer_periodic,
&timer,
time_out,
timer_flag_periodic[i]);
/* calc expect tick */
timer.expect_tick = rt_tick_get() + time_out;
/* start timer */
result = rt_timer_start(&timer.static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* wait for timerout */
rt_thread_delay(time_out + 1);
/* detach timer */
result = rt_timer_detach(&timer.static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
if (timer.test_flag != RT_TRUE)
{
uassert_true(RT_FALSE);
return;
}
}
}
timer.test_flag = RT_FALSE;
uassert_true(RT_TRUE);
return;
}
static void static_timer_control(void *param)
{
rt_err_t result;
timer_struct *timer_call;
timer_call = (timer_struct *)param;
timer_call->test_flag = RT_TRUE;
/* check expect tick */
if (rt_tick_get() - timer_call->expect_tick > 1)
{
uassert_true(RT_FALSE);
}
/* periodic timer can stop */
result = rt_timer_stop(&timer_call->static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
return;
}
static void test_static_timer_control(void)
{
rt_err_t result;
int rand_num = rand() % 10;
int set_data;
int get_data;
rt_timer_init(&timer.static_timer,
"static_timer",
static_timer_control,
&timer,
5,
RT_TIMER_FLAG_PERIODIC);
/* test set data */
set_data = rand_num;
result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
/* test get data */
result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
/* a set of test */
if (set_data != get_data)
{
uassert_true(RT_FALSE);
}
/* calc expect tick */
timer.expect_tick = rt_tick_get() + set_data;
/* start timer */
result = rt_timer_start(&timer.static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
rt_thread_delay(set_data + 1);
/* detach timer */
result = rt_timer_detach(&timer.static_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
if (timer.test_flag != RT_TRUE)
{
uassert_true(RT_FALSE);
return;
}
timer.test_flag = RT_FALSE;
uassert_true(RT_TRUE);
}
#ifdef RT_USING_HEAP
#define test_dynamic_timer_start test_dynamic_timer_create
#define test_dynamic_timer_stop test_dynamic_timer_create
#define test_dynamic_timer_delete test_dynamic_timer_create
static void dynamic_timer_oneshot(void *param)
{
timer_struct *timer_call;
timer_call = (timer_struct *)param;
timer_call->test_flag = RT_TRUE;
/* check expect tick */
if (rt_tick_get() - timer_call->expect_tick > 1)
{
uassert_true(RT_FALSE);
}
return;
}
static void dynamic_timer_periodic(void *param)
{
rt_err_t result;
timer_struct *timer_call;
timer_call = (timer_struct *)param;
timer_call->test_flag = RT_TRUE;
/* check expect tick */
if (rt_tick_get() - timer_call->expect_tick > 1)
{
uassert_true(RT_FALSE);
}
/* periodic timer can stop */
result = rt_timer_stop(timer_call->dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
return;
}
static void test_dynamic_timer_create(void)
{
rt_err_t result;
int rand_num = rand() % 10;
/* one shot timer test */
for (int time_out = 0; time_out < rand_num; time_out++)
{
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
{
timer.dynamic_timer = rt_timer_create("dynamic_timer",
dynamic_timer_oneshot,
&timer,
time_out,
timer_flag_oneshot[i]);
/* calc expect tick */
timer.expect_tick = rt_tick_get() + time_out;
/* start timer */
result = rt_timer_start(timer.dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* wait for timerout */
rt_thread_delay(time_out + 1);
/* detach timer */
result = rt_timer_delete(timer.dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
if (timer.test_flag != RT_TRUE)
{
uassert_true(RT_FALSE);
return;
}
}
}
/* periodic timer test */
for (int time_out = 0; time_out < rand_num; time_out++)
{
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
{
timer.dynamic_timer = rt_timer_create("dynamic_timer",
dynamic_timer_periodic,
&timer,
time_out,
timer_flag_periodic[i]);
/* calc expect tick */
timer.expect_tick = rt_tick_get() + time_out;
/* start timer */
result = rt_timer_start(timer.dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
/* wait for timerout */
rt_thread_delay(time_out + 1);
/* detach timer */
result = rt_timer_delete(timer.dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
if (timer.test_flag != RT_TRUE)
{
uassert_true(RT_FALSE);
return;
}
}
}
timer.test_flag = RT_FALSE;
uassert_true(RT_TRUE);
return;
}
static void dynamic_timer_control(void *param)
{
rt_err_t result;
timer_struct *timer_call;
timer_call = (timer_struct *)param;
timer_call->test_flag = RT_TRUE;
/* check expect tick */
if (rt_tick_get() - timer_call->expect_tick > 1)
{
uassert_true(RT_FALSE);
}
/* periodic timer can stop */
result = rt_timer_stop(timer_call->dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
return;
}
static void test_dynamic_timer_control(void)
{
rt_err_t result;
int rand_num = rand() % 10;
int set_data;
int get_data;
timer.dynamic_timer = rt_timer_create("dynamic_timer",
dynamic_timer_control,
&timer,
5,
RT_TIMER_FLAG_PERIODIC);
/* test set data */
set_data = rand_num;
result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
/* test get data */
result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
}
/* a set of test */
if (set_data != get_data)
{
uassert_true(RT_FALSE);
}
/* calc expect tick */
timer.expect_tick = rt_tick_get() + set_data;
/* start timer */
result = rt_timer_start(timer.dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
rt_thread_delay(set_data + 1);
/* detach timer */
result = rt_timer_delete(timer.dynamic_timer);
if (RT_EOK != result)
{
uassert_true(RT_FALSE);
return;
}
if (timer.test_flag != RT_TRUE)
{
uassert_true(RT_FALSE);
return;
}
timer.test_flag = RT_FALSE;
uassert_true(RT_TRUE);
}
#endif /* RT_USING_HEAP */
static rt_err_t utest_tc_init(void)
{
timer.dynamic_timer = RT_NULL;
timer.test_flag = RT_FALSE;
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
timer.dynamic_timer = RT_NULL;
timer.test_flag = RT_FALSE;
return RT_EOK;
}
static void testcase(void)
{
UTEST_UNIT_RUN(test_static_timer_init);
UTEST_UNIT_RUN(test_static_timer_start);
UTEST_UNIT_RUN(test_static_timer_stop);
UTEST_UNIT_RUN(test_static_timer_detach);
UTEST_UNIT_RUN(test_static_timer_control);
#ifdef RT_USING_HEAP
UTEST_UNIT_RUN(test_dynamic_timer_create);
UTEST_UNIT_RUN(test_dynamic_timer_start);
UTEST_UNIT_RUN(test_dynamic_timer_stop);
UTEST_UNIT_RUN(test_dynamic_timer_delete);
UTEST_UNIT_RUN(test_dynamic_timer_control);
#endif /* RT_USING_HEAP */
}
UTEST_TC_EXPORT(testcase, "testcases.kernel.timer_tc", utest_tc_init, utest_tc_cleanup, 1000);
/*********************** end of file ****************************/

View file

@ -0,0 +1,17 @@
menu "Memory Management Subsytem Testcase"
config UTEST_MM_API_TC
bool "Enable Utest for MM API"
default n
help
The test covers the Memory Management APIs under the
`components/mm` and `libcpu/[mmu.*|tlb.*|cache.*]`
config UTEST_MM_LWP_TC
bool "Enable Utest for MM API in lwp"
default n
help
The test covers the Memory Management APIs under the
`components/lwp`.
endmenu

View file

@ -0,0 +1,16 @@
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]
if GetDepend(['UTEST_MM_API_TC']):
src += ['mm_api_tc.c', 'mm_libcpu_tc.c']
if GetDepend(['UTEST_MM_LWP_TC']):
src += ['mm_lwp_tc.c']
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c
*/
#ifndef __TEST_MM_COMMON_H__
#define __TEST_MM_COMMON_H__
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <utest.h>
#include <board.h>
#include <rtthread.h>
#include <rthw.h>
#include <lwp_arch.h>
#include <mmu.h>
#include <tlb.h>
#include <ioremap.h>
#include <mm_aspace.h>
#include <mm_flag.h>
#include <mm_page.h>
#include <mm_private.h>
extern rt_base_t rt_heap_lock(void);
extern void rt_heap_unlock(rt_base_t level);
/**
* @brief During the operations, is heap still the same;
*/
#define CONSIST_HEAP(statement) do { \
rt_size_t total, used, max_used; \
rt_size_t totala, useda, max_useda; \
rt_ubase_t level = rt_heap_lock(); \
rt_memory_info(&total, &used, &max_used); \
statement; \
rt_memory_info(&totala, &useda, &max_useda); \
rt_heap_unlock(level); \
uassert_true(total == totala); \
uassert_true(used == useda); \
uassert_true(max_used == max_useda); \
} while (0)
rt_inline int memtest(volatile char *buf, int value, size_t buf_sz)
{
int ret = 0;
for (size_t i = 0; i < buf_sz; i++)
{
if (buf[i] != value)
{
ret = -1;
break;
}
}
return ret;
}
#endif /* __TEST_MM_COMMON_H__ */

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-12-14 WangXiaoyao the first version
* 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h
*/
#include "common.h"
/**
* @brief Testing all APIs under components/mm
*/
void ioremap_tc(void);
void flag_tc(void);
#ifdef STANDALONE_TC
#define TC_ASSERT(expr) \
((expr) \
? 0 \
: rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr)))
#else
#define TC_ASSERT(expr) uassert_true(expr)
#endif
static rt_err_t utest_tc_init(void)
{
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
return RT_EOK;
}
#include "test_aspace_api.h"
static void testcase(void)
{
UTEST_UNIT_RUN(aspace_tc);
UTEST_UNIT_RUN(ioremap_tc);
UTEST_UNIT_RUN(flag_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.mm.api_tc", utest_tc_init, utest_tc_cleanup, 20);
void ioremap_tc(void)
{
const size_t bufsz = 0x1000;
void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET;
int *vaddr;
vaddr = rt_ioremap_cached(paddr, bufsz);
if (vaddr)
{
TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET));
rt_iounmap(vaddr);
rt_pages_free(paddr - PV_OFFSET, 0);
}
}
void flag_tc(void)
{
size_t flags;
flags = MMF_CREATE(MMF_MAP_FIXED, 0x4000);
TC_ASSERT(MMF_GET_CNTL(flags) == (MMF_MAP_FIXED | MMF_REQUEST_ALIGN));
TC_ASSERT((1 << MMF_GET_ALIGN(flags)) == 0x4000);
flags = MMF_CREATE(MMF_MAP_FIXED, 0);
TC_ASSERT(MMF_GET_CNTL(flags) == MMF_MAP_FIXED);
TC_ASSERT(MMF_GET_ALIGN(flags) == 0);
}
#if 0
#define BUF_SIZE (4ul << 20)
static char ALIGN(BUF_SIZE) buf[BUF_SIZE];
void buddy_tc(void)
{
size_t total, free;
rt_page_get_info(&total, &free);
rt_region_t region = {
.start = (size_t)buf,
.end = (size_t)buf + BUF_SIZE,
};
size_t new_total, new_free;
rt_page_install(region);
rt_page_get_info(&new_total, &new_free);
TC_ASSERT(new_total - total == (BUF_SIZE >> ARCH_PAGE_SHIFT));
TC_ASSERT(new_free > free);
}
void mmu_page_tc()
{
mm_aspace_t aspace = ASPACE_NEW();
size_t total, free;
rt_page_get_info(&total, &free);
rt_hw_mmu_map(aspace, (void *)0x3fffffffff, 0, ARCH_PAGE_SIZE,
MMU_MAP_K_RWCB);
rt_hw_mmu_unmap(aspace, (void *)0x3fffffffff, ARCH_PAGE_SIZE);
size_t new_total, new_free;
rt_page_get_info(&new_total, &new_free);
TC_ASSERT(new_free == free);
mm_aspace_delete(aspace);
}
#endif

View file

@ -0,0 +1,16 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-17 WangXiaoyao cache API unit test
*/
#include <rtthread.h>
#ifdef ARCH_RISCV64
#include "test_cache_rv64.h"
#elif defined(ARCH_ARMV8)
#include "test_cache_aarch64.h"
#endif

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-27 WangXiaoyao testcase for lwp
*/
#include "common.h"
#include <lwp.h>
#include "lwp_arch.h"
#include "lwp_user_mm.h"
#include "mm_aspace.h"
#include "mmu.h"
/**
* @brief user map API
* rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size);
* rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags);
*/
#if 1 /* make it clear to identify the block :) */
/* for testing on _aspace_traverse */
static void *_prev_end;
static size_t _count;
static int _test_increase(rt_varea_t varea, void *param)
{
uassert_true(varea->start >= _prev_end);
_prev_end = varea->start + varea->size;
_count += 1;
return 0;
}
#define TEST_VAREA_INSERT(statement, aspace) do {\
size_t _prev_count; \
_count = 0; \
_prev_end = 0; \
rt_aspace_traversal((aspace), _test_increase, NULL);\
_prev_count = _count; \
statement; \
_count = 0; \
_prev_end = 0; \
rt_aspace_traversal((aspace), _test_increase, NULL);\
uassert_true(_prev_count + 1 == _count); \
} while (0)
#endif
static void test_user_map_varea(void)
{
const size_t buf_sz = ARCH_PAGE_SIZE * 4;
struct rt_lwp *lwp;
rt_varea_t varea;
lwp = lwp_new();
uassert_true(!!lwp);
uassert_true(!lwp_user_space_init(lwp, 0));
TEST_VAREA_INSERT(
varea = lwp_map_user_varea(lwp, 0, buf_sz),
lwp->aspace);
uassert_true(!!varea);
uassert_true(varea->attr == (MMU_MAP_U_RWCB));
uassert_true(varea->size == buf_sz);
uassert_true(varea->aspace == lwp->aspace);
uassert_true(varea->flag == 0);
uassert_true(varea->start != 0);
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
uassert_true(!lwp_ref_dec(lwp));
}
static void test_user_map_varea_ext(void)
{
const size_t buf_sz = ARCH_PAGE_SIZE * 4;
struct rt_lwp *lwp;
rt_varea_t varea;
lwp = lwp_new();
uassert_true(!!lwp);
uassert_true(!lwp_user_space_init(lwp, 0));
TEST_VAREA_INSERT(
varea = lwp_map_user_varea_ext(lwp, 0, buf_sz, LWP_MAP_FLAG_NOCACHE),
lwp->aspace);
uassert_true(!!varea);
uassert_true(varea->attr == (MMU_MAP_U_RW));
uassert_true(varea->size == buf_sz);
uassert_true(varea->aspace == lwp->aspace);
uassert_true(varea->flag == 0);
uassert_true(varea->start != 0);
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
uassert_true(!lwp_ref_dec(lwp));
}
static void user_map_varea_tc(void)
{
CONSIST_HEAP(test_user_map_varea());
CONSIST_HEAP(test_user_map_varea_ext());
}
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(user_map_varea_tc);
}
UTEST_TC_EXPORT(testcase, "testcases.lwp.mm_tc", utest_tc_init, utest_tc_cleanup, 20);

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-24 WangXiaoyao Complete testcase for synchronization
*/
#ifndef __SEMAPHORE_H__
#define __SEMAPHORE_H__
#include <stdatomic.h>
typedef struct {
atomic_int count;
} semaphore_t;
void semaphore_init(semaphore_t *sem, int count)
{
atomic_init(&sem->count, count);
}
void semaphore_wait(semaphore_t *sem)
{
int count;
do {
count = atomic_load(&sem->count);
} while (count == 0 || !atomic_compare_exchange_weak(&sem->count, &count, count - 1));
}
void semaphore_signal(semaphore_t *sem)
{
atomic_fetch_add(&sem->count, 1);
}
#endif /* __SEMAPHORE_H__ */

View file

@ -0,0 +1,287 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c
*/
#ifndef __TEST_ASPACE_API_H__
#define __TEST_ASPACE_API_H__
#include "common.h"
#include "lwp_arch.h"
#include "test_aspace_api_internal.h"
#include "test_synchronization.h"
/**
* @brief API for aspace create/destroy
*
* rt_aspace_t rt_aspace_create(void *start, rt_size_t length, void *pgtbl);
* rt_aspace_t rt_aspace_init(rt_aspace_t aspace, void *start, rt_size_t length, void *pgtbl);
* void rt_aspace_delete(rt_aspace_t aspace);
* void rt_aspace_detach(rt_aspace_t aspace);
*
* the init & detach is covered by create & detach
*/
static void aspace_create_tc(void)
{
/* test robustness, detect failure and recover status of overall system */
rt_aspace_t aspace;
CONSIST_HEAP(aspace = rt_aspace_create((void *)(0 - 0x1000), 0x1000, NULL));
uassert_true(!aspace);
}
#if 1 /* make it clear to identify the block :) */
/* for testing on _aspace_traverse */
static void *_prev_end;
static size_t _count;
static int _test_increase(rt_varea_t varea, void *param)
{
uassert_true(varea->start >= _prev_end);
_prev_end = varea->start + varea->size;
_count += 1;
return 0;
}
#endif
static void aspace_delete_tc(void)
{
/**
* @brief Requirements: delete should recycle all types of vareas properly inside
* and release the resource allocated for it
*/
rt_aspace_t aspace;
struct rt_mm_va_hint hint = {.flags = 0,
.map_size = 0x1000,
.prefer = 0};
struct rt_varea varea_phy;
struct rt_varea varea_mobj;
void *pgtbl;
void *vaddr;
/* compatible to armv7a */
pgtbl = rt_pages_alloc(2);
uassert_true(!!pgtbl); /* page must be usable */
rt_memset(pgtbl, 0, ARCH_PAGE_SIZE);
CONSIST_HEAP({
aspace = rt_aspace_create((void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, pgtbl);
uassert_true(!!aspace);
/* insert 4 types of vareas into this aspace */
hint.limit_start = aspace->start;
hint.limit_range_size = aspace->size;
uassert_true(!rt_aspace_map_phy(aspace, &hint, MMU_MAP_K_RWCB, 0, &vaddr));
uassert_true(!rt_aspace_map_phy_static(aspace, &varea_phy, &hint, MMU_MAP_K_RWCB, 0, &vaddr));
uassert_true(!rt_aspace_map(aspace, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
uassert_true(!rt_aspace_map_static(aspace, &varea_mobj, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
/* for testing on _aspace_traverse */
_count = 0;
_prev_end = 0;
uassert_true(!rt_aspace_traversal(aspace, _test_increase, 0));
/* ensure the mapping is done */
uassert_true(_count == 4);
rt_aspace_delete(aspace);
uassert_true(rt_pages_free(pgtbl, 2) == 1); /* page free must success */
});
}
/**
* @brief Memory Map on Virtual Address Space to Mappable Object
* int rt_aspace_map(rt_aspace_t aspace, void **addr, rt_size_t length, rt_size_t attr,
* mm_flag_t flags, rt_mem_obj_t mem_obj, rt_size_t offset);
* int rt_aspace_map_static(rt_aspace_t aspace, rt_varea_t varea, void **addr,
* rt_size_t length, rt_size_t attr, mm_flag_t flags,
* rt_mem_obj_t mem_obj, rt_size_t offset);
*/
static void aspace_map_tc(void)
{
/**
* @brief Requirement:
* Robustness, filter out invalid input
*/
void *vaddr = RT_NULL;
uassert_true(rt_aspace_map(0, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
uassert_true(vaddr == RT_NULL);
vaddr = (void *)USER_VADDR_START;
uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
uassert_true(vaddr == RT_NULL);
uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, -1, &rt_mm_dummy_mapper, 0));
uassert_true(vaddr == RT_NULL);
/**
* @brief Requirement:
* in _rt_aspace_map:_varea_install
* not covering an existed varea if a named mapping is mandatory
*/
vaddr = (void *)((rt_ubase_t)aspace_map_tc & ~ARCH_PAGE_MASK);
CONSIST_HEAP(
uassert_true(
rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0)));
uassert_true(vaddr == RT_NULL);
/**
* @brief Requirement:
* in _rt_aspace_map:_varea_install:_find_free
* verify that this routine can choose a free region with specified size
* and specified alignment requirement
*/
#define ALIGN_REQ (0x04000000)
CONSIST_HEAP({
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_CREATE(0, ALIGN_REQ), &rt_mm_dummy_mapper, 0));
uassert_true(!((rt_ubase_t)vaddr & (ALIGN_REQ - 1)));
rt_aspace_unmap(&rt_kernel_space, vaddr);
});
/* test internal APIs */
test_find_free();
}
/**
* @brief Page frames mapping to varea
* complete the page table on specified varea, and handle tlb maintenance
* There are 2 variants of this API
*
* int rt_varea_map_page(rt_varea_t varea, void *vaddr, void *page);
* int rt_varea_map_range(rt_varea_t varea, void *vaddr, void *paddr, rt_size_t length);
*/
static rt_varea_t _create_varea(const size_t size)
{
rt_varea_t varea;
void *vaddr = rt_ioremap_start;
varea = rt_malloc(sizeof(*varea));
uassert_true(!!varea);
uassert_true(!rt_aspace_map_static(&rt_kernel_space, varea, &vaddr, size, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
varea->flag &= ~MMF_STATIC_ALLOC;
uassert_true(!!vaddr);
return varea;
}
static void test_varea_map_page(void)
{
/**
* @brief rt_varea_map_page
* Requirements: complete the page table entry
*/
const size_t buf_sz = 4 * ARCH_PAGE_SIZE;
rt_varea_t varea = _create_varea(buf_sz);
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
{
void *page = rt_pages_alloc(0);
uassert_true(!!page);
uassert_true(!rt_varea_map_page(varea, varea->start + i, page));
/* let page manager handle the free of page */
rt_varea_pgmgr_insert(varea, page);
uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET));
}
uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start));
}
static void test_varea_map_range(void)
{
/**
* @brief rt_varea_map_range
* Requirements: complete the page table entry
*/
const size_t buf_sz = 4 * ARCH_PAGE_SIZE;
rt_varea_t varea = _create_varea(buf_sz);
void *page = rt_pages_alloc(rt_page_bits(buf_sz));
uassert_true(!!page);
uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz));
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
{
uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET));
}
uassert_true(rt_pages_free(page, rt_page_bits(buf_sz)));
uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start));
}
static void varea_map_tc(void)
{
CONSIST_HEAP(test_varea_map_page());
CONSIST_HEAP(test_varea_map_range());
}
static void aspace_traversal_tc(void)
{
/**
* @brief Requirement
* Iterate over each varea in the kernel space
*/
CONSIST_HEAP(aspace_delete_tc());
uassert_true(4 == _count);
}
#ifdef ARCH_ARMV8
static void aspace_control_tc(void)
{
/* this case is designed only for one page size */
const size_t buf_sz = ARCH_PAGE_SIZE;
void *vaddr = RT_NULL;
volatile char *remap_nocache;
int platform_cache_probe;
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0));
uassert_true(!!vaddr);
/* map non-cacheable region to verify cache */
remap_nocache = rt_ioremap(rt_kmem_v2p(vaddr), buf_sz);
uassert_true(!!remap_nocache);
/* pre probing */
rt_memset(vaddr, 0xba, buf_sz);
/* no need to sync transaction on same core */
platform_cache_probe = memtest(remap_nocache, 0xab, buf_sz);
if (!platform_cache_probe)
{
LOG_I("Cannot distinguish cache attribution on current platform");
}
else
{
LOG_I("Ready to verify attribution of cached & non-cacheable");
}
/* verify cache */
uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_NONCACHE));
rt_memset(vaddr, 0, buf_sz);
uassert_true(!memtest(remap_nocache, 0, buf_sz));
/* another option as MMU_CNTL_CACHE */
uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_CACHE));
rt_iounmap(remap_nocache);
uassert_true(!rt_aspace_unmap(&rt_kernel_space, vaddr));
}
#endif
static void aspace_tc(void)
{
UTEST_UNIT_RUN(aspace_create_tc);
UTEST_UNIT_RUN(aspace_delete_tc);
UTEST_UNIT_RUN(aspace_map_tc);
UTEST_UNIT_RUN(aspace_traversal_tc);
#ifdef ARCH_ARMV8
UTEST_UNIT_RUN(aspace_control_tc);
#endif
UTEST_UNIT_RUN(varea_map_tc);
/* functionality */
UTEST_UNIT_RUN(synchronization_tc);
return ;
}
#endif /* __TEST_ASPACE_API_H__ */

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-23 WangXiaoyao Complete testcase for internal APIs
*/
#ifndef __TEST_ASPACE_API_INTERNAL_H__
#define __TEST_ASPACE_API_INTERNAL_H__
#include "common.h"
#include "mmu.h"
#include "test_bst_adpt.h"
#include <stddef.h>
/**
* @brief 3 cases for find free:
* with prefer & MAP_FIXED
* with prefer
* without prefer
*
* the requirement of find free:
* it will return a subset in address space that is free
* the subset contains `length` contiguous elements
* the alignment is satisfied
*/
static void test_find_free(void)
{
void *top_page = rt_kernel_space.start + rt_kernel_space.size - 0x1000;
void *vaddr = top_page;
CONSIST_HEAP({
/* type 1, on success */
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0));
uassert_true(vaddr == top_page);
/* type 1, on failure */
uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0));
uassert_true(!vaddr);
/* type 2, on success */
vaddr = top_page;
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
uassert_true(vaddr < top_page);
uassert_true(!!vaddr);
rt_aspace_unmap(&rt_kernel_space, vaddr);
/* type 2, on failure */
vaddr = rt_kernel_space.start;
uassert_true(-RT_ENOSPC == rt_aspace_map(&rt_kernel_space, &vaddr, rt_kernel_space.size - 0x08000000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
uassert_true(!vaddr);
/* type 3, on success is covered by ioremap */
/* type 3, on failure */
size_t map_size = ARCH_PAGE_SIZE;
while (1)
{
void *va = rt_ioremap(0, map_size);
if (va)
{
uassert_true(1);
rt_iounmap(va);
map_size <<= 1;
}
else
{
uassert_true(1);
break;
}
}
/* free top page */
rt_aspace_unmap(&rt_kernel_space, top_page);
});
/* test mm_private.h */
CONSIST_HEAP(test_bst_adpt());
}
#endif /* __TEST_ASPACE_API_INTERNAL_H__ */

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-23 WangXiaoyao Complete testcase for internal APIs
*/
#ifndef __TEST_BST_ADPT_H__
#define __TEST_BST_ADPT_H__
#include "common.h"
#include "lwp_arch.h"
#ifdef RT_USING_SMART
#include "lwp_user_mm.h"
#include "mm_aspace.h"
#include "mm_flag.h"
#include <mm_private.h>
#include <lwp_pid.h>
void test_bst_adpt(void)
{
size_t flags = MMF_MAP_FIXED;
void *target_va = (void *)USER_VADDR_START + 0x3000;
size_t map_size = 0x1000;
void *prev_va = target_va - map_size;
void *next_va = target_va + map_size + 1;
struct rt_lwp *lwp;
rt_aspace_t aspace;
rt_mem_obj_t mem_obj;
/* create aspace by lwp */
lwp = lwp_new();
uassert_true(!!lwp);
uassert_true(!lwp_user_space_init(lwp, 0));
aspace = lwp->aspace;
mem_obj = &lwp->lwp_obj->mem_obj;
uassert_true(!!aspace);
uassert_true(!!mem_obj);
/* _aspace_bst_search not cover */
uassert_true(!_aspace_bst_search(aspace, target_va)); // ret == NULL
uassert_true(
!rt_aspace_map(aspace, &target_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0));
/* 2 wrappers */
uassert_true(
!rt_aspace_map(aspace, &prev_va, map_size - 1, MMU_MAP_K_RWCB, flags, mem_obj, 0));
uassert_true(
!rt_aspace_map(aspace, &next_va, map_size - 1, MMU_MAP_K_RWCB, flags, mem_obj, 0));
/* _aspace_bst_search */
uassert_true(!!_aspace_bst_search(aspace, target_va));
uassert_true(!_aspace_bst_search(aspace, target_va + map_size));
uassert_true(!_aspace_bst_search(aspace, target_va - 1));
/**
* @brief _aspace_bst_search_exceed
* for given map [start, end]
*/
rt_varea_t find;
find = _aspace_bst_search_exceed(aspace, target_va);
uassert_true(!!find);
uassert_true(find->start == target_va);
rt_varea_t last = ASPACE_VAREA_LAST(aspace);
find = _aspace_bst_search_exceed(aspace, last->start + 1);
uassert_true(!find);
/**
* @brief _aspace_bst_search_overlap
* for given map [start, end], five types of overlapping
*/
/* 1. all below */
struct _mm_range range = {.start = prev_va - 2, .end = prev_va - 1};
find = _aspace_bst_search_overlap(aspace, range);
uassert_true(!find);
/* 2. start below */
range.end = prev_va;
find = _aspace_bst_search_overlap(aspace, range);
uassert_true(!!find);
uassert_true(find->start == prev_va);
/* 3. all wrapped */
range.start = prev_va;
range.end = prev_va + 1;
find = _aspace_bst_search_overlap(aspace, range);
uassert_true(!!find);
uassert_true(find->start == prev_va);
/* 4. end exceed */
range.start = next_va;
range.end = next_va + map_size + 1;
find = _aspace_bst_search_overlap(aspace, range);
uassert_true(!!find);
uassert_true(find->start == next_va);
/* 5. all exceed */
range.start = next_va + map_size;
find = _aspace_bst_search_overlap(aspace, range);
uassert_true(!find);
lwp_ref_dec(lwp);
}
#endif /* RT_USING_SMART */
#endif /* __TEST_BST_ADPT_H__ */

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-17 WangXiaoyao cache API unit test
*/
#ifndef __TEST_CACHE_AARCH64_H__
#define __TEST_CACHE_AARCH64_H__
#include "common.h"
#include <cache.h>
const char *platform_cache_not_guarantee = "Cannot guarantee cache operation works";
/**
* ==============================================================
* TEST FEATURE
* API under cache.h
*
* void rt_hw_icache_invalidate_range(unsigned long start_addr, int size);
* void rt_hw_cpu_icache_invalidate(void *addr, rt_size_t size);
* void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, rt_size_t size);
* ==============================================================
*/
static int _get1_const(void)
{
return 1;
}
static int _get1(void)
{
return 1;
}
static int _get2(void)
{
return 2;
}
/* hot patching codes and test if the value can be seen by icache */
static void _test_icache_invalidate_range(void)
{
/* reset _get1 */
rt_memcpy(_get1, _get1_const, _get2 - _get1);
rt_hw_cpu_dcache_clean(_get1, _get2 - _get1);
rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1);
uassert_true(1 == _get1());
/* now copy _get2 to _get1 */
rt_memcpy(_get1, _get2, _get2 - _get1);
if (1 != _get1())
LOG_W(platform_cache_not_guarantee);
rt_hw_cpu_dcache_clean(_get1, _get2 - _get1);
rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1);
__asm__ volatile("isb");
uassert_true(2 == _get1());
LOG_I("%s ok", __func__);
}
/* due to hardware feature of cortex-a, we should done this on 2 separated cpu */
static void _test_dcache_clean_and_invalidate(void)
{
const size_t padding = 1024 * 2;
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
volatile char *remap_nocache;
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
uassert_true(!!page);
rt_memset(page, 0xab, buf_sz);
rt_hw_cpu_dcache_invalidate(page, buf_sz);
int _outdate_flag = 0;
if (memtest(page, 0xab, buf_sz))
_outdate_flag = 1;
/* after ioremap, we can access system memory to verify outcome */
remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE);
memtest(remap_nocache + padding, 0xab, ARCH_PAGE_SIZE);
if (!_outdate_flag)
LOG_W(platform_cache_not_guarantee);
else
LOG_I("%s ok", __func__);
rt_pages_free(page, 0);
rt_iounmap(remap_nocache);
}
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)
{
/* todo: format API under cache.h first */
UTEST_UNIT_RUN(_test_icache_invalidate_range);
UTEST_UNIT_RUN(_test_dcache_clean_and_invalidate);
}
UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10);
#endif /* __TEST_CACHE_AARCH64_H__ */

View file

@ -0,0 +1,194 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-17 WangXiaoyao cache API unit test
*/
#ifndef __TEST_CACHE_RV64_H
#define __TEST_CACHE_RV64_H
#ifdef ARCH_RISCV64
#include "riscv_mmu.h"
#include <utest.h>
#include <cache.h>
#include <page.h>
#include <mmu.h>
#include <ioremap.h>
/**
* ==============================================================
* TEST FEATURE
* API under cache.h
* rt_hw_sync_cache_local
*
* rt_hw_cpu_dcache_clean
* rt_hw_cpu_dcache_invalidate
* rt_hw_cpu_dcache_clean_invalidate
* rt_hw_cpu_dcache_clean_all
* rt_hw_cpu_dcache_invalidate_all // meaningless
* rt_hw_cpu_dcache_clean_invalidate_all
* rt_hw_cpu_icache_invalidate
* rt_hw_cpu_icache_invalidate_all
* ==============================================================
*/
/* Ensure the ISA is valid for target ARCHITECTURE */
static void _illegal_instr(void)
{
rt_hw_sync_cache_local(_illegal_instr, 64);
rt_hw_cpu_dcache_clean(_illegal_instr, 64);
rt_hw_cpu_dcache_invalidate(_illegal_instr, 64);
// rt_hw_cpu_dcache_clean_invalidate(_illegal_instr, 64); // C908 ONLY
rt_hw_cpu_dcache_clean_all();
rt_hw_cpu_dcache_invalidate_all(); // !CAREFUL must be inline
// rt_hw_cpu_dcache_clean_invalidate_all(); // C908 ONLY
rt_hw_cpu_icache_invalidate(_illegal_instr, 64);
rt_hw_cpu_icache_invalidate_all();
uassert_true(1);
LOG_I("All ok!");
}
static int _get1(void)
{
return 1;
}
static int _get2(void)
{
return 2;
}
/* hot patching codes and test if the value can be seen by icache */
static void _test_cache_sync(void)
{
uassert_true(1 == _get1());
rt_memcpy(_get1, _get2, _get2 - _get1);
uassert_true(1 == _get1());
rt_hw_sync_cache_local(_get1, _get2 - _get1);
uassert_true(2 == _get1());
LOG_I("%s ok", __func__);
}
/* test clean operation should do and only effect the range specified by writing to a page */
static void _test_dcache_clean(void)
{
const size_t padding = 1024 * 3;
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
uassert_true(!!page);
/* after ioremap, we can access system memory to verify outcome */
volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
rt_memset(page, 0xab, buf_sz);
rt_hw_cpu_sync();
int _outdate_flag = 0;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
if (remap_nocache[i] != 0xab)
{
_outdate_flag = 1;
break;
}
}
page[padding - 1] = 0xac;
page[padding + ARCH_PAGE_SIZE] = 0xac;
rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE);
/* free some space in dcache to avoid padding data being written back */
rt_hw_cpu_dcache_invalidate(page + padding, ARCH_PAGE_SIZE);
uassert_true(remap_nocache[padding - 1] != 0xac);
uassert_true(remap_nocache[padding + ARCH_PAGE_SIZE] != 0xac);
int _test_ok = 1;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
if (remap_nocache[i] != 0xab)
{
_test_ok = 0;
break;
}
}
uassert_true(_test_ok);
if (!_outdate_flag)
LOG_W("Cannot guarantee clean works");
else
LOG_I("%s ok", __func__);
rt_pages_free(page, 0);
rt_iounmap(remap_nocache);
}
/* test clean op should do and only effect the range */
static void _test_dcache_invalidate(void)
{
const size_t padding = 1024 * 3;
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
/* prepare */
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
uassert_true(!!page);
volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
rt_memset(page, 0x0, buf_sz);
rt_hw_cpu_sync();
int _outdate_flag = 0;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
remap_nocache[i] = 0xab;
rt_hw_cpu_dcache_invalidate((void *)&remap_nocache[i], 1);
}
rt_hw_cpu_dcache_clean_all();
int _test_ok = 1;
for (size_t i = padding; i < ARCH_PAGE_SIZE; i++)
{
if (remap_nocache[i] == 0xab)
{
_test_ok = 0;
break;
}
}
uassert_true(_test_ok);
LOG_I("%s ok", __func__);
rt_pages_free(page, 0);
rt_iounmap(remap_nocache);
}
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(_illegal_instr);
#ifdef BOARD_allwinnerd1s
/* thead ISA extension */
UTEST_UNIT_RUN(_test_cache_sync);
/* part of it is hard to test on simulation machine */
UTEST_UNIT_RUN(_test_dcache_clean);
UTEST_UNIT_RUN(_test_dcache_invalidate);
#endif
}
UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10);
#endif /* ARCH_RISCV64 */
#endif /* __TEST_CACHE_RV64_H */

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-24 WangXiaoyao Complete testcase for synchronization
*/
#ifndef __TEST_SYNCHRONIZATION_H__
#define __TEST_SYNCHRONIZATION_H__
#include "common.h"
#include "semaphore.h"
#ifdef RT_USING_SMP
#define THREAD_CNT RT_CPUS_NR
#define TEST_TIMES 2000
#define PRIO (UTEST_THR_PRIORITY + 1)
/* size of mapping buffer */
#define BUF_SIZE (64ul << 10)
/* engage with sibling */
struct rt_semaphore done;
static semaphore_t sem1[THREAD_CNT / 2];
static semaphore_t sem2[THREAD_CNT / 2];
static void *map(void)
{
int err;
int flags = MMF_PREFETCH;
size_t attr = MMU_MAP_K_RWCB;
void *vaddr = 0;
err =
rt_aspace_map(&rt_kernel_space, &vaddr, BUF_SIZE, attr, flags, &rt_mm_dummy_mapper, 0);
if (err)
uassert_true(0);
return vaddr;
}
static void unmap(void *buf)
{
int err;
err =
rt_aspace_unmap(&rt_kernel_space, buf);
if (err)
uassert_true(0);
return ;
}
static void group1_entry(void *param)
{
const size_t id = (size_t)param;
size_t test_times = TEST_TIMES;
size_t alive = test_times / 10;
void *buf;
while (test_times--)
{
if (test_times % alive == 0)
uassert_true(1);
buf = map();
memset(buf, 'A' + id, BUF_SIZE);
/* if other core write to our cache, force the changes to be visible to us */
rt_hw_dmb();
if (memtest(buf, 'A' + id, BUF_SIZE))
uassert_true(0);
semaphore_signal(&sem1[id]);
semaphore_wait(&sem2[id]);
unmap(buf);
}
rt_sem_release(&done);
return;
}
static void group2_entry(void *param)
{
const size_t id = (size_t)param;
size_t test_times = TEST_TIMES;
size_t alive = test_times / 10;
void *buf;
while (test_times--)
{
if (test_times % alive == 0)
uassert_true(1);
semaphore_signal(&sem2[id]);
semaphore_wait(&sem1[id]);
buf = map();
memset(buf, 'a' + id, BUF_SIZE);
/* if other core write to our cache, force the changes to be visible to us */
rt_hw_dmb();
if (memtest(buf, 'a' + id, BUF_SIZE))
uassert_true(0);
unmap(buf);
}
rt_sem_release(&done);
return;
}
/**
* @brief On a smp system, we create at least 4 threads
* 2 doing map, 2 doing unmapping at the same moment
*/
static void synchronization_tc(void)
{
rt_thread_t group1[THREAD_CNT / 2];
rt_thread_t group2[THREAD_CNT / 2];
rt_sem_init(&done, __func__, 0, RT_IPC_FLAG_FIFO);
for (size_t i = 0; i < THREAD_CNT / 2; i++)
{
char name[RT_NAME_MAX];
rt_sprintf(name, "grp1_%d", i);
group1[i] =
rt_thread_create(name, group1_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10);
uassert_true(!!group1[i]);
semaphore_init(&sem1[i], 0);
uassert_true(!rt_thread_startup(group1[i]));
}
for (size_t i = 0; i < THREAD_CNT / 2; i++)
{
char name[RT_NAME_MAX];
rt_sprintf(name, "grp2_%d", i);
group2[i] =
rt_thread_create(name, group2_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10);
uassert_true(!!group2[i]);
semaphore_init(&sem2[i], 0);
uassert_true(!rt_thread_startup(group2[i]));
}
/* wait all thread exit */
for (size_t i = 0; i < (THREAD_CNT / 2 * 2); i++)
{
rt_sem_take(&done, RT_WAITING_FOREVER);
}
LOG_I("all threads exit");
rt_sem_detach(&done);
}
#else /* RT_USING_SMP */
static void synchronization_tc(void)
{
uassert_true(1);
}
#endif /* RT_USING_SMP */
#endif /* __TEST_SYNCHRONIZATION_H__ */

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