import RT-Thread@9217865c without bsp, libcpu and components/net
This commit is contained in:
commit
e2376a3709
1414 changed files with 390370 additions and 0 deletions
90
examples/file/listdir.c
Normal file
90
examples/file/listdir.c
Normal 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
89
examples/file/readspeed.c
Normal 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
170
examples/file/readwrite.c
Normal 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
53
examples/file/seekdir.c
Normal 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
100
examples/file/writespeed.c
Normal 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
6
examples/libc/SConscript
Normal 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
59
examples/libc/dirent.c
Normal 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
22
examples/libc/env.c
Normal 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
45
examples/libc/ex1.c
Normal 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
122
examples/libc/ex2.c
Normal 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
162
examples/libc/ex3.c
Normal 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
116
examples/libc/ex4.c
Normal 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
113
examples/libc/ex5.c
Normal 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
45
examples/libc/ex6.c
Normal 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
109
examples/libc/ex7.c
Normal 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
520
examples/libc/file.c
Normal 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
60
examples/libc/memory.c
Normal 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
129
examples/libc/mq.c
Normal 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
210
examples/libc/printf.c
Normal 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
47
examples/libc/rand.c
Normal 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
74
examples/libc/sem.c
Normal 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);
|
351
examples/libc/termios_test.c
Normal file
351
examples/libc/termios_test.c
Normal 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
27
examples/libc/time.c
Normal 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
244
examples/network/chargen.c
Normal 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
|
16
examples/network/tcp_client.py
Normal file
16
examples/network/tcp_client.py
Normal 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()
|
34
examples/network/tcp_server.py
Normal file
34
examples/network/tcp_server.py
Normal 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))
|
||||
|
260
examples/network/tcpclient.c
Normal file
260
examples/network/tcpclient.c
Normal 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_STREAM,TCP类型 */
|
||||
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
|
89
examples/network/tcpsendpacket.c
Normal file
89
examples/network/tcpsendpacket.c
Normal 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_STREAM,TCP类型 */
|
||||
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
|
||||
|
286
examples/network/tcpserver.c
Normal file
286
examples/network/tcpserver.c
Normal 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
|
182
examples/network/udpclient.c
Normal file
182
examples/network/udpclient.c
Normal 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_DGRAM,UDP类型 */
|
||||
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
|
214
examples/network/udpserver.c
Normal file
214
examples/network/udpserver.c
Normal 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_DGRAM,UDP类型 */
|
||||
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
55
examples/pm/timer_app.c
Normal 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
77
examples/pm/wakeup_app.c
Normal 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
|
400
examples/rt-link/rtlink_dev_example.c
Normal file
400
examples/rt-link/rtlink_dev_example.c
Normal 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);
|
214
examples/rt-link/rtlink_example.c
Normal file
214
examples/rt-link/rtlink_example.c
Normal 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
585
examples/test/avl.c
Normal 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
516
examples/test/device_test.c
Normal 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
412
examples/test/dhry.h
Normal 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
349
examples/test/dhry_1.c
Normal 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
192
examples/test/dhry_2.c
Normal 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
297
examples/test/fs_test.c
Normal 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
|
111
examples/test/hwtimer_test.c
Normal file
111
examples/test/hwtimer_test.c
Normal 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
114
examples/test/mem_test.c
Normal 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
345
examples/test/net_test.c
Normal 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
327
examples/test/rbb_test.c
Normal 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)
|
||||
|
106
examples/test/ringbuffer_test.c
Normal file
106
examples/test/ringbuffer_test.c
Normal 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
61
examples/test/rtc_test.c
Normal 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
|
93
examples/ulog/ulog_example.c
Normal file
93
examples/ulog/ulog_example.c
Normal 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
73
examples/utest/README.md
Normal 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 主仓库提交合并请求。
|
4
examples/utest/configs/cpp11/cpp11.conf
Normal file
4
examples/utest/configs/cpp11/cpp11.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_UTEST_CPP11_THREAD_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_CPLUSPLUS=y
|
||||
CONFIG_RT_USING_CPLUSPLUS11=y
|
4
examples/utest/configs/kernel/atomic.conf
Normal file
4
examples/utest/configs/kernel/atomic.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_UTEST_ATOMIC_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
5
examples/utest/configs/kernel/atomic_c11.conf
Normal file
5
examples/utest/configs/kernel/atomic_c11.conf
Normal 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
|
13
examples/utest/configs/kernel/ipc.conf
Normal file
13
examples/utest/configs/kernel/ipc.conf
Normal 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
|
3
examples/utest/configs/kernel/irq.conf
Normal file
3
examples/utest/configs/kernel/irq.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
CONFIG_UTEST_IRQ_TC=y
|
||||
CONFIG_RT_HOOK_USING_FUNC_PTR=y
|
||||
# dependencies
|
4
examples/utest/configs/kernel/mem.conf
Normal file
4
examples/utest/configs/kernel/mem.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
4
examples/utest/configs/kernel/thread.conf
Normal file
4
examples/utest/configs/kernel/thread.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_UTEST_THREAD_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
4
examples/utest/configs/kernel/timer.conf
Normal file
4
examples/utest/configs/kernel/timer.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_UTEST_TIMER_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
5
examples/utest/configs/rtsmart/base.conf
Normal file
5
examples/utest/configs/rtsmart/base.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_SMART=y
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
1
examples/utest/configs/utest_self/self.conf
Normal file
1
examples/utest/configs/utest_self/self.conf
Normal file
|
@ -0,0 +1 @@
|
|||
CONFIG_UTEST_SELF_PASS_TC=y
|
19
examples/utest/testcases/Kconfig
Normal file
19
examples/utest/testcases/Kconfig
Normal 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
|
15
examples/utest/testcases/SConscript
Normal file
15
examples/utest/testcases/SConscript
Normal 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')
|
9
examples/utest/testcases/cpp11/Kconfig
Normal file
9
examples/utest/testcases/cpp11/Kconfig
Normal 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
|
13
examples/utest/testcases/cpp11/SConscript
Normal file
13
examples/utest/testcases/cpp11/SConscript
Normal 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')
|
59
examples/utest/testcases/cpp11/thread_tc.cpp
Normal file
59
examples/utest/testcases/cpp11/thread_tc.cpp
Normal 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);
|
15
examples/utest/testcases/drivers/SConscript
Normal file
15
examples/utest/testcases/drivers/SConscript
Normal 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')
|
7
examples/utest/testcases/drivers/serial_v2/Kconfig
Normal file
7
examples/utest/testcases/drivers/serial_v2/Kconfig
Normal file
|
@ -0,0 +1,7 @@
|
|||
menu "Utest Serial Testcase"
|
||||
|
||||
config UTEST_SERIAL_TC
|
||||
bool "Serial testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
120
examples/utest/testcases/drivers/serial_v2/README.md
Normal file
120
examples/utest/testcases/drivers/serial_v2/README.md
Normal 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和B,A为接收线程,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` 中对串口相应的宏进行配置,来选择不同的工作模式去进行测试。
|
||||
|
16
examples/utest/testcases/drivers/serial_v2/SConscript
Normal file
16
examples/utest/testcases/drivers/serial_v2/SConscript
Normal 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')
|
230
examples/utest/testcases/drivers/serial_v2/uart_rxb_txb.c
Normal file
230
examples/utest/testcases/drivers/serial_v2/uart_rxb_txb.c
Normal 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 */
|
263
examples/utest/testcases/drivers/serial_v2/uart_rxb_txnb.c
Normal file
263
examples/utest/testcases/drivers/serial_v2/uart_rxb_txnb.c
Normal 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
|
266
examples/utest/testcases/drivers/serial_v2/uart_rxnb_txb.c
Normal file
266
examples/utest/testcases/drivers/serial_v2/uart_rxnb_txb.c
Normal 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 */
|
294
examples/utest/testcases/drivers/serial_v2/uart_rxnb_txnb.c
Normal file
294
examples/utest/testcases/drivers/serial_v2/uart_rxnb_txnb.c
Normal 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
|
62
examples/utest/testcases/kernel/Kconfig
Normal file
62
examples/utest/testcases/kernel/Kconfig
Normal 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
|
49
examples/utest/testcases/kernel/SConscript
Normal file
49
examples/utest/testcases/kernel/SConscript
Normal 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')
|
170
examples/utest/testcases/kernel/atomic_tc.c
Normal file
170
examples/utest/testcases/kernel/atomic_tc.c
Normal 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);
|
344
examples/utest/testcases/kernel/event_tc.c
Normal file
344
examples/utest/testcases/kernel/event_tc.c
Normal 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);
|
78
examples/utest/testcases/kernel/irq_tc.c
Normal file
78
examples/utest/testcases/kernel/irq_tc.c
Normal 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);
|
371
examples/utest/testcases/kernel/mailbox_tc.c
Normal file
371
examples/utest/testcases/kernel/mailbox_tc.c
Normal 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);
|
588
examples/utest/testcases/kernel/mem_tc.c
Normal file
588
examples/utest/testcases/kernel/mem_tc.c
Normal 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);
|
97
examples/utest/testcases/kernel/memheap_tc.c
Normal file
97
examples/utest/testcases/kernel/memheap_tc.c
Normal 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);
|
192
examples/utest/testcases/kernel/messagequeue_tc.c
Normal file
192
examples/utest/testcases/kernel/messagequeue_tc.c
Normal 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);
|
676
examples/utest/testcases/kernel/mutex_tc.c
Normal file
676
examples/utest/testcases/kernel/mutex_tc.c
Normal 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 ************************/
|
558
examples/utest/testcases/kernel/semaphore_tc.c
Normal file
558
examples/utest/testcases/kernel/semaphore_tc.c
Normal 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);
|
199
examples/utest/testcases/kernel/signal_tc.c
Normal file
199
examples/utest/testcases/kernel/signal_tc.c
Normal 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 ****************************/
|
323
examples/utest/testcases/kernel/slab_tc.c
Normal file
323
examples/utest/testcases/kernel/slab_tc.c
Normal 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);
|
743
examples/utest/testcases/kernel/thread_tc.c
Normal file
743
examples/utest/testcases/kernel/thread_tc.c
Normal 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 ************************/
|
520
examples/utest/testcases/kernel/timer_tc.c
Normal file
520
examples/utest/testcases/kernel/timer_tc.c
Normal 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 ****************************/
|
17
examples/utest/testcases/mm/Kconfig
Normal file
17
examples/utest/testcases/mm/Kconfig
Normal 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
|
16
examples/utest/testcases/mm/SConscript
Normal file
16
examples/utest/testcases/mm/SConscript
Normal 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')
|
65
examples/utest/testcases/mm/common.h
Normal file
65
examples/utest/testcases/mm/common.h
Normal 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__ */
|
113
examples/utest/testcases/mm/mm_api_tc.c
Normal file
113
examples/utest/testcases/mm/mm_api_tc.c
Normal 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
|
16
examples/utest/testcases/mm/mm_libcpu_tc.c
Normal file
16
examples/utest/testcases/mm/mm_libcpu_tc.c
Normal 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
|
116
examples/utest/testcases/mm/mm_lwp_tc.c
Normal file
116
examples/utest/testcases/mm/mm_lwp_tc.c
Normal 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);
|
37
examples/utest/testcases/mm/semaphore.h
Normal file
37
examples/utest/testcases/mm/semaphore.h
Normal 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__ */
|
287
examples/utest/testcases/mm/test_aspace_api.h
Normal file
287
examples/utest/testcases/mm/test_aspace_api.h
Normal 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__ */
|
80
examples/utest/testcases/mm/test_aspace_api_internal.h
Normal file
80
examples/utest/testcases/mm/test_aspace_api_internal.h
Normal 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__ */
|
107
examples/utest/testcases/mm/test_bst_adpt.h
Normal file
107
examples/utest/testcases/mm/test_bst_adpt.h
Normal 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__ */
|
115
examples/utest/testcases/mm/test_cache_aarch64.h
Normal file
115
examples/utest/testcases/mm/test_cache_aarch64.h
Normal 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__ */
|
194
examples/utest/testcases/mm/test_cache_rv64.h
Normal file
194
examples/utest/testcases/mm/test_cache_rv64.h
Normal 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 */
|
165
examples/utest/testcases/mm/test_synchronization.h
Normal file
165
examples/utest/testcases/mm/test_synchronization.h
Normal 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
Loading…
Add table
Add a link
Reference in a new issue