原始版本
This commit is contained in:
90
RT_Thread/examples/file/listdir.c
Normal file
90
RT_Thread/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
RT_Thread/examples/file/readspeed.c
Normal file
89
RT_Thread/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
RT_Thread/examples/file/readwrite.c
Normal file
170
RT_Thread/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
RT_Thread/examples/file/seekdir.c
Normal file
53
RT_Thread/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
RT_Thread/examples/file/writespeed.c
Normal file
100
RT_Thread/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
RT_Thread/examples/libc/SConscript
Normal file
6
RT_Thread/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
RT_Thread/examples/libc/dirent.c
Normal file
59
RT_Thread/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
RT_Thread/examples/libc/env.c
Normal file
22
RT_Thread/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
RT_Thread/examples/libc/ex1.c
Normal file
45
RT_Thread/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
RT_Thread/examples/libc/ex2.c
Normal file
122
RT_Thread/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
RT_Thread/examples/libc/ex3.c
Normal file
162
RT_Thread/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
RT_Thread/examples/libc/ex4.c
Normal file
116
RT_Thread/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
RT_Thread/examples/libc/ex5.c
Normal file
113
RT_Thread/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
RT_Thread/examples/libc/ex6.c
Normal file
45
RT_Thread/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_delay
|
||||
|
||||
static void *test_thread(void *v_param) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int libc_ex6(void) {
|
||||
unsigned long count;
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
for (count = 0; count < 2000; ++count) {
|
||||
pthread_t thread;
|
||||
int status;
|
||||
|
||||
status = pthread_create(&thread, NULL, test_thread, NULL);
|
||||
if (status != 0) {
|
||||
printf("status = %d, count = %lu: %s\n", status, count, strerror(
|
||||
errno));
|
||||
return 1;
|
||||
} else {
|
||||
printf("count = %lu\n", count);
|
||||
}
|
||||
/* pthread_detach (thread); */
|
||||
pthread_join(thread, NULL);
|
||||
usleep(10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#include <finsh.h>
|
||||
FINSH_FUNCTION_EXPORT(libc_ex6, example 6 for libc);
|
||||
109
RT_Thread/examples/libc/ex7.c
Normal file
109
RT_Thread/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_delay
|
||||
|
||||
/* Our event variable using a condition variable contruct. */
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
int flag;
|
||||
} event_t;
|
||||
|
||||
/* Global event to signal main thread the timeout of the child thread. */
|
||||
event_t main_event;
|
||||
|
||||
static void *test_thread(void *ms_param) {
|
||||
int status = 0;
|
||||
event_t foo;
|
||||
struct timespec time;
|
||||
struct timeval now;
|
||||
long ms = (long) ms_param;
|
||||
|
||||
/* initialize cond var */
|
||||
pthread_cond_init(&foo.cond, NULL);
|
||||
pthread_mutex_init(&foo.mutex, NULL);
|
||||
foo.flag = 0;
|
||||
|
||||
/* set the time out value */
|
||||
printf("waiting %ld ms ...\n", ms);
|
||||
gettimeofday(&now, NULL);
|
||||
time.tv_sec = now.tv_sec + ms / 1000 + (now.tv_usec + (ms % 1000) * 1000)
|
||||
/ 1000000;
|
||||
time.tv_nsec = ((now.tv_usec + (ms % 1000) * 1000) % 1000000) * 1000;
|
||||
|
||||
/* Just use this to test the time out. The cond var is never signaled. */
|
||||
pthread_mutex_lock(&foo.mutex);
|
||||
while (foo.flag == 0 && status != ETIMEDOUT) {
|
||||
status = pthread_cond_timedwait(&foo.cond, &foo.mutex, &time);
|
||||
}
|
||||
pthread_mutex_unlock(&foo.mutex);
|
||||
|
||||
/* post the main event */
|
||||
pthread_mutex_lock(&main_event.mutex);
|
||||
main_event.flag = 1;
|
||||
pthread_cond_signal(&main_event.cond);
|
||||
pthread_mutex_unlock(&main_event.mutex);
|
||||
|
||||
/* that's it, bye */
|
||||
return (void*) status;
|
||||
}
|
||||
|
||||
int libc_ex7(void) {
|
||||
unsigned long count;
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
/* initialize main event cond var */
|
||||
pthread_cond_init(&main_event.cond, NULL);
|
||||
pthread_mutex_init(&main_event.mutex, NULL);
|
||||
main_event.flag = 0;
|
||||
|
||||
for (count = 0; count < 20; ++count) {
|
||||
pthread_t thread;
|
||||
int status;
|
||||
|
||||
/* pass down the milli-second timeout in the void* param */
|
||||
status = pthread_create(&thread, NULL, test_thread, (void*) (count
|
||||
* 100));
|
||||
if (status != 0) {
|
||||
printf("status = %d, count = %lu: %s\n", status, count, strerror(
|
||||
errno));
|
||||
return 1;
|
||||
} else {
|
||||
|
||||
/* wait for the event posted by the child thread */
|
||||
pthread_mutex_lock(&main_event.mutex);
|
||||
while (main_event.flag == 0) {
|
||||
pthread_cond_wait(&main_event.cond, &main_event.mutex);
|
||||
}
|
||||
main_event.flag = 0;
|
||||
pthread_mutex_unlock(&main_event.mutex);
|
||||
|
||||
printf("count = %lu\n", count);
|
||||
}
|
||||
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include <finsh.h>
|
||||
FINSH_FUNCTION_EXPORT(libc_ex7, example 7 for libc);
|
||||
520
RT_Thread/examples/libc/file.c
Normal file
520
RT_Thread/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_delay(tick);
|
||||
}
|
||||
|
||||
int libc_fseek(void)
|
||||
{
|
||||
const char *tmpdir;
|
||||
char *fname;
|
||||
int fd;
|
||||
FILE *fp;
|
||||
const char outstr[] = "hello world!\n";
|
||||
char strbuf[sizeof outstr];
|
||||
char buf[200];
|
||||
struct stat st1;
|
||||
struct stat st2;
|
||||
int result = 0;
|
||||
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (tmpdir == NULL || tmpdir[0] == '\0')
|
||||
tmpdir = "/tmp";
|
||||
|
||||
asprintf(&fname, "%s/tst-fseek.XXXXXX", tmpdir);
|
||||
if (fname == NULL)
|
||||
{
|
||||
fprintf(stderr, "cannot generate name for temporary file: %s\n",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create a temporary file. */
|
||||
fd = mkstemp(fname);
|
||||
if (fd == -1)
|
||||
{
|
||||
fprintf(stderr, "cannot open temporary file: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp = fdopen(fd, "w+");
|
||||
if (fp == NULL)
|
||||
{
|
||||
fprintf(stderr, "cannot get FILE for temporary file: %s\n", strerror(
|
||||
errno));
|
||||
return 1;
|
||||
}
|
||||
setbuffer(fp, strbuf, sizeof(outstr) - 1);
|
||||
|
||||
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: write error\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The EOF flag must be reset. */
|
||||
if (fgetc(fp) != EOF)
|
||||
{
|
||||
printf("%d: managed to read at end of file\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (!feof(fp))
|
||||
{
|
||||
printf("%d: EOF flag not set\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (feof(fp))
|
||||
{
|
||||
printf("%d: fseek() didn't reset EOF flag\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Do the same for fseeko(). */
|
||||
if (fgetc(fp) != EOF)
|
||||
{
|
||||
printf("%d: managed to read at end of file\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (!feof(fp))
|
||||
{
|
||||
printf("%d: EOF flag not set\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
if (fseeko(fp, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (feof(fp))
|
||||
{
|
||||
printf("%d: fseek() didn't reset EOF flag\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Go back to the beginning of the file: absolute. */
|
||||
if (fseek(fp, 0, SEEK_SET) != 0)
|
||||
{
|
||||
printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fflush(fp) != 0)
|
||||
{
|
||||
printf("%d: fflush() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (lseek(fd, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
int pos = lseek(fd, 0, SEEK_CUR);
|
||||
printf("%d: lseek() returned different position, pos %d\n", __LINE__,
|
||||
pos);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: fread() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
|
||||
{
|
||||
printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Now with fseeko. */
|
||||
if (fseeko(fp, 0, SEEK_SET) != 0)
|
||||
{
|
||||
printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fflush(fp) != 0)
|
||||
{
|
||||
printf("%d: fflush() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (lseek(fd, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: lseek() returned different position\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: fread() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
|
||||
{
|
||||
printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Go back to the beginning of the file: relative. */
|
||||
if (fseek(fp, -((int) sizeof(outstr) - 1), SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fflush(fp) != 0)
|
||||
{
|
||||
printf("%d: fflush() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (lseek(fd, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: lseek() returned different position\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: fread() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
|
||||
{
|
||||
printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Now with fseeko. */
|
||||
if (fseeko(fp, -((int) sizeof(outstr) - 1), SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fflush(fp) != 0)
|
||||
{
|
||||
printf("%d: fflush() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (lseek(fd, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: lseek() returned different position\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: fread() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
|
||||
{
|
||||
printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Go back to the beginning of the file: from the end. */
|
||||
if (fseek(fp, -((int) sizeof(outstr) - 1), SEEK_END) != 0)
|
||||
{
|
||||
printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fflush(fp) != 0)
|
||||
{
|
||||
printf("%d: fflush() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (lseek(fd, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: lseek() returned different position\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: fread() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
|
||||
{
|
||||
printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Now with fseeko. */
|
||||
if (fseeko(fp, -((int) sizeof(outstr) - 1), SEEK_END) != 0)
|
||||
{
|
||||
printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fflush(fp) != 0)
|
||||
{
|
||||
printf("%d: fflush() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (lseek(fd, 0, SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: lseek() returned different position\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: fread() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
|
||||
{
|
||||
printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: write error 2\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: write error 3\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: write error 4\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
|
||||
{
|
||||
printf("%d: write error 5\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fputc('1', fp) == EOF || fputc('2', fp) == EOF)
|
||||
{
|
||||
printf("%d: cannot add characters at the end\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check the access time. */
|
||||
if (fstat(fd, &st1) < 0)
|
||||
{
|
||||
printf("%d: fstat64() before fseeko() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
if (fseek(fp, -(2 + 2 * (sizeof(outstr) - 1)), SEEK_CUR) != 0)
|
||||
{
|
||||
printf("%d: fseek() after write characters failed\n", __LINE__);
|
||||
result = 1;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
time_t t;
|
||||
/* Make sure the timestamp actually can be different. */
|
||||
sleep(1);
|
||||
t = time(NULL);
|
||||
|
||||
if (fstat(fd, &st2) < 0)
|
||||
{
|
||||
printf("%d: fstat64() after fseeko() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
if (st1.st_ctime >= t)
|
||||
{
|
||||
printf("%d: st_ctime not updated\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
if (st1.st_mtime >= t)
|
||||
{
|
||||
printf("%d: st_mtime not updated\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
if (st1.st_ctime >= st2.st_ctime)
|
||||
{
|
||||
printf("%d: st_ctime not changed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
if (st1.st_mtime >= st2.st_mtime)
|
||||
{
|
||||
printf("%d: st_mtime not changed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fread(buf, 1, 2 + 2 * (sizeof(outstr) - 1), fp) != 2 + 2
|
||||
* (sizeof(outstr) - 1))
|
||||
{
|
||||
printf("%d: reading 2 records plus bits failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0 || memcmp(
|
||||
&buf[sizeof(outstr) - 1], outstr, sizeof(outstr) - 1) != 0 || buf[2
|
||||
* (sizeof(outstr) - 1)] != '1' || buf[2 * (sizeof(outstr) - 1) + 1]
|
||||
!= '2')
|
||||
{
|
||||
printf("%d: reading records failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (ungetc('9', fp) == EOF)
|
||||
{
|
||||
printf("%d: ungetc() failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fseek(fp, -(2 + 2 * (sizeof(outstr) - 1)), SEEK_END) != 0)
|
||||
{
|
||||
printf("%d: fseek after ungetc failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fread(buf, 1, 2 + 2 * (sizeof(outstr) - 1), fp) != 2 + 2
|
||||
* (sizeof(outstr) - 1))
|
||||
{
|
||||
printf("%d: reading 2 records plus bits failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0 || memcmp(
|
||||
&buf[sizeof(outstr) - 1], outstr, sizeof(outstr) - 1) != 0 || buf[2
|
||||
* (sizeof(outstr) - 1)] != '1')
|
||||
{
|
||||
printf("%d: reading records for the second time failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (buf[2 * (sizeof(outstr) - 1) + 1] == '9')
|
||||
{
|
||||
printf("%d: unget character not ignored\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (buf[2 * (sizeof(outstr) - 1) + 1] != '2')
|
||||
{
|
||||
printf("%d: unget somehow changed character\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("%d: fopen() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fstat(fileno(fp), &st1) < 0)
|
||||
{
|
||||
printf("%d: fstat64() before fseeko() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fseeko(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
printf("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (ftello(fp) != st1.st_size)
|
||||
{
|
||||
printf("%d: fstat64 st_size %zd ftello %zd\n", __LINE__,
|
||||
(size_t) st1.st_size, (size_t) ftello(fp));
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
printf("%d: SEEK_END works\n", __LINE__);
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("%d: fopen() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fstat(fileno(fp), &st1) < 0)
|
||||
{
|
||||
printf("%d: fstat64() before fgetc() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fgetc(fp) == EOF)
|
||||
{
|
||||
printf("%d: fgetc() before fseeko() failed\n\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (fseeko(fp, 0, SEEK_END) != 0)
|
||||
{
|
||||
printf("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__);
|
||||
result = 1;
|
||||
}
|
||||
else if (ftello(fp) != st1.st_size)
|
||||
{
|
||||
printf("%d: fstat64 st_size %zd ftello %zd\n", __LINE__,
|
||||
(size_t) st1.st_size, (size_t) ftello(fp));
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
printf("%d: SEEK_END works\n", __LINE__);
|
||||
if (fp != NULL)
|
||||
fclose(fp);
|
||||
|
||||
out: unlink(fname);
|
||||
|
||||
return result;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(libc_fseek, lseek test for libc);
|
||||
60
RT_Thread/examples/libc/memory.c
Normal file
60
RT_Thread/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
RT_Thread/examples/libc/mq.c
Normal file
129
RT_Thread/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
RT_Thread/examples/libc/printf.c
Normal file
210
RT_Thread/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
RT_Thread/examples/libc/rand.c
Normal file
47
RT_Thread/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
RT_Thread/examples/libc/sem.c
Normal file
74
RT_Thread/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
RT_Thread/examples/libc/termios_test.c
Normal file
351
RT_Thread/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
RT_Thread/examples/libc/time.c
Normal file
27
RT_Thread/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
RT_Thread/examples/network/chargen.c
Normal file
244
RT_Thread/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
RT_Thread/examples/network/tcp_client.py
Normal file
16
RT_Thread/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
RT_Thread/examples/network/tcp_server.py
Normal file
34
RT_Thread/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))
|
||||
|
||||
266
RT_Thread/examples/network/tcpclient.c
Normal file
266
RT_Thread/examples/network/tcpclient.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-01-24 ChungHsuan improve code comments
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(SAL_USING_POSIX)
|
||||
#error "Please enable SAL_USING_POSIX!"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket,需要包含socket.h头文件 */
|
||||
#include "netdb.h"
|
||||
|
||||
#define DEBUG_TCP_CLIENT
|
||||
|
||||
#define DBG_TAG "TCP"
|
||||
#ifdef DEBUG_TCP_CLIENT
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO /* DBG_ERROR */
|
||||
#endif
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define BUFSZ 1024
|
||||
|
||||
static int started = 0;
|
||||
static int is_running = 0;
|
||||
static char url[256];
|
||||
static int port = 8080;
|
||||
static const char send_data[] = "This is TCP Client from RT-Thread."; /* The message be sent */ /* 发送用到的数据 */
|
||||
|
||||
/**
|
||||
* @brief This function is for creating a tcp client on RT-Thread
|
||||
*/
|
||||
static void tcpclient(void *arg)
|
||||
{
|
||||
int ret;
|
||||
char *recv_data;
|
||||
int bytes_received;
|
||||
int sock = -1;
|
||||
struct hostent *host = RT_NULL;
|
||||
struct sockaddr_in server_addr;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set readset;
|
||||
/* Get host address by parameter url(Domain name resolution if input domain) */
|
||||
/* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */
|
||||
host = gethostbyname(url);
|
||||
if (host == RT_NULL)
|
||||
{
|
||||
LOG_E("Get host by name failed!");
|
||||
return;
|
||||
}
|
||||
/* Allocate space for recv_data */
|
||||
/* 分配用于存放接收数据的缓冲 */
|
||||
recv_data = rt_malloc(BUFSZ);
|
||||
if (recv_data == RT_NULL)
|
||||
{
|
||||
LOG_E("No memory");
|
||||
return;
|
||||
}
|
||||
/* Create a socket and set it to SOCK_STREAM(TCP) */
|
||||
/* 创建一个socket,类型是SOCKET_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(%d), close the socket.", errno);
|
||||
goto __exit;
|
||||
}
|
||||
else if (bytes_received == 0)
|
||||
{
|
||||
/* Socket has performed an orderly shutdown. */
|
||||
/* 连接已断开 */
|
||||
LOG_E("Socket has performed an orderly shutdown.");
|
||||
goto __exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Receive data successfully and append '\0' at the end of message */
|
||||
/* 有接收到数据,把末端清零 */
|
||||
recv_data[bytes_received] = '\0';
|
||||
|
||||
if (rt_strcmp(recv_data, "q") == 0 || rt_strcmp(recv_data, "Q") == 0)
|
||||
{
|
||||
/* If the first letter is 'q' or 'Q', close the connection */
|
||||
/* 如果是首字母是q或Q,关闭这个连接 */
|
||||
LOG_I("Got a 'q' or 'Q', close the socket.");
|
||||
goto __exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Show the message in terminal */
|
||||
/* 在控制终端显示收到的数据 */
|
||||
LOG_D("Received data = %s", recv_data);
|
||||
}
|
||||
}
|
||||
/* Send message to connected socket */
|
||||
/* 发送数据到sock连接 */
|
||||
ret = send(sock, send_data, rt_strlen(send_data), 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Send failed, close the connection */
|
||||
/* 发送失败,关闭这个连接 */
|
||||
LOG_I("send error(%d), close the socket.", errno);
|
||||
goto __exit;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* Socket has performed an orderly shutdown. */
|
||||
/* 连接已断开 */
|
||||
LOG_E("Socket has performed an orderly shutdown.");
|
||||
goto __exit;
|
||||
}
|
||||
else if (ret != rt_strlen(send_data))
|
||||
{
|
||||
LOG_W("%d out of %d bytes sent.", ret, rt_strlen(send_data));
|
||||
}
|
||||
}
|
||||
|
||||
__exit:
|
||||
if (recv_data)
|
||||
{
|
||||
rt_free(recv_data);
|
||||
recv_data = RT_NULL;
|
||||
}
|
||||
if (sock >= 0)
|
||||
{
|
||||
closesocket(sock);
|
||||
sock = -1;
|
||||
}
|
||||
started = 0;
|
||||
is_running = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The usage description of tcp client on rt-Thread
|
||||
*/
|
||||
static void usage(void)
|
||||
{
|
||||
rt_kprintf("Usage: tcpclient -h <host> -p <port>\n");
|
||||
rt_kprintf(" tcpclient --stop\n");
|
||||
rt_kprintf(" tcpclient --help\n");
|
||||
rt_kprintf("\n");
|
||||
rt_kprintf("Miscellaneous:\n");
|
||||
rt_kprintf(" -h Specify host address\n");
|
||||
rt_kprintf(" -p Specify the host port number\n");
|
||||
rt_kprintf(" --stop Stop tcpclient program\n");
|
||||
rt_kprintf(" --help Print help information\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is for testing tcp client on rt-Thread
|
||||
*/
|
||||
static void tcpclient_test(int argc, char** argv)
|
||||
{
|
||||
rt_thread_t tid;
|
||||
|
||||
if (argc == 1 || argc > 5)
|
||||
{
|
||||
LOG_I("Please check the command you entered!\n");
|
||||
goto __usage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_strcmp(argv[1], "--help") == 0)
|
||||
{
|
||||
goto __usage;
|
||||
}
|
||||
else if (rt_strcmp(argv[1], "--stop") == 0)
|
||||
{
|
||||
is_running = 0;
|
||||
return;
|
||||
}
|
||||
else if (rt_strcmp(argv[1], "-h") == 0 && rt_strcmp(argv[3], "-p") == 0)
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
LOG_I("The tcpclient has started!");
|
||||
LOG_I("Please stop tcpclient firstly, by: tcpclient --stop");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt_strlen(argv[2]) > sizeof(url))
|
||||
{
|
||||
LOG_E("The input url is too long, max %d bytes!", sizeof(url));
|
||||
return;
|
||||
}
|
||||
rt_memset(url, 0x0, sizeof(url));
|
||||
rt_strncpy(url, argv[2], rt_strlen(argv[2]));
|
||||
port = atoi(argv[4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto __usage;
|
||||
}
|
||||
}
|
||||
|
||||
tid = rt_thread_create("tcp_client",
|
||||
tcpclient, RT_NULL,
|
||||
2048, RT_THREAD_PRIORITY_MAX/3, 20);
|
||||
if (tid != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(tid);
|
||||
}
|
||||
return;
|
||||
|
||||
__usage:
|
||||
usage();
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
MSH_CMD_EXPORT_ALIAS(tcpclient_test, tcpclient,
|
||||
Start a tcp client. Help: tcpclient --help);
|
||||
#endif
|
||||
89
RT_Thread/examples/network/tcpsendpacket.c
Normal file
89
RT_Thread/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
|
||||
|
||||
296
RT_Thread/examples/network/tcpserver.c
Normal file
296
RT_Thread/examples/network/tcpserver.c
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-01-24 ChungHsuan improve code comments
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(SAL_USING_POSIX)
|
||||
#error "Please enable SAL_USING_POSIX!"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket,需要包含socket.h头文件 */
|
||||
#include "netdb.h"
|
||||
|
||||
#define DEBUG_TCP_SERVER
|
||||
|
||||
#define DBG_TAG "TCP"
|
||||
#ifdef DEBUG_TCP_SERVER
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO /* DBG_ERROR */
|
||||
#endif
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define BUFSZ (1024)
|
||||
|
||||
static int started = 0;
|
||||
static int is_running = 0;
|
||||
static int port = 5000;
|
||||
static const char send_data[] = "This is TCP Server from RT-Thread."; /* The message be sent */ /* 发送用到的数据 */
|
||||
|
||||
/**
|
||||
* @brief This function is for creating a tcp server on RT-Thread
|
||||
*/
|
||||
static void tcpserv(void *arg)
|
||||
{
|
||||
int ret;
|
||||
char *recv_data; /* recv_data is a pointer used to receive data */ /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */
|
||||
int sock, connected, bytes_received;
|
||||
struct sockaddr_in server_addr, client_addr;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set readset, readset_c;
|
||||
socklen_t sin_size = sizeof(struct sockaddr_in);
|
||||
|
||||
recv_data = rt_malloc(BUFSZ + 1);/* Allocate space for recv_data */ /* 分配接收用的数据缓冲 */
|
||||
if (recv_data == RT_NULL)
|
||||
{
|
||||
LOG_E("No memory");
|
||||
return;
|
||||
}
|
||||
/* Before making use of socket, socket should be created first and set the socket created to SOCK_STREAM(TCP) */
|
||||
/* 一个socket在使用前,需要预先创建出来,指定SOCK_STREAM为TCP的socket */
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
LOG_E("Create socket error");
|
||||
goto __exit;
|
||||
}
|
||||
/* Initialize server side address */
|
||||
/* 初始化服务端地址 */
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(port); /*Server side port number*//* 服务端工作的端口 */
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
rt_memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
|
||||
/* Bind socket to server side address */
|
||||
/* 绑定socket到服务端地址 */
|
||||
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
|
||||
{
|
||||
LOG_E("Unable to bind");
|
||||
goto __exit;
|
||||
}
|
||||
/* Listen on socket */
|
||||
/* 在socket上进行监听 */
|
||||
if (listen(sock, 10) == -1)
|
||||
{
|
||||
LOG_E("Listen error");
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
LOG_I("\nTCPServer Waiting for client on port %d...\n", port);
|
||||
|
||||
started = 1;
|
||||
is_running = 1;
|
||||
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
while (is_running)
|
||||
{
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(sock, &readset);
|
||||
|
||||
LOG_I("Waiting for a new connection...");
|
||||
|
||||
/* Wait for read or write */
|
||||
if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
|
||||
continue;
|
||||
/* Accept a request from client and the function is blocking */
|
||||
/* 接受一个客户端连接socket的请求,这个函数调用是阻塞式的 */
|
||||
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
|
||||
/* Return the socket connected successfully */
|
||||
/* 返回的是连接成功的socket */
|
||||
if (connected < 0)
|
||||
{
|
||||
LOG_E("accept connection failed! errno = %d", errno);
|
||||
continue;
|
||||
}
|
||||
/* Accept the message which points by client address */
|
||||
/* 接受返回的client_addr指向了客户端的地址信息 */
|
||||
LOG_I("I got a connection from (%s , %d)\n",
|
||||
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
|
||||
/* Handle method of client connection */
|
||||
/* 客户端连接的处理 */
|
||||
while (is_running)
|
||||
{
|
||||
FD_ZERO(&readset_c);
|
||||
FD_SET(connected, &readset_c);
|
||||
|
||||
/* Wait for read or write */
|
||||
if (select(connected + 1, &readset_c, RT_NULL, RT_NULL, &timeout) == 0)
|
||||
continue;
|
||||
/* Receive message from connected socket. Buffer size is 1024 bytes,but it's not guranteed to receive size exactly 1024 */
|
||||
/* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */
|
||||
bytes_received = recv(connected, recv_data, BUFSZ, 0);
|
||||
if (bytes_received < 0)
|
||||
{
|
||||
LOG_E("Received error(%d), close the connect.", errno);
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
break;
|
||||
}
|
||||
else if (bytes_received == 0)
|
||||
{
|
||||
/* Socket has performed an orderly shutdown */
|
||||
/* 连接已断开 */
|
||||
LOG_E("Socket has performed an orderly shutdown.");
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{ /* Receive data successfully and append '\0' at the end of message */
|
||||
/* 有接收到数据,把末端清零 */
|
||||
recv_data[bytes_received] = '\0';
|
||||
if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
|
||||
{
|
||||
/* If the first letter is 'q' or 'Q', close the connection */
|
||||
/* 如果是首字母是q或Q,关闭这个连接 */
|
||||
LOG_I("Got a 'q' or 'Q', close the connect.");
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
break;
|
||||
}
|
||||
else if (strcmp(recv_data, "exit") == 0)
|
||||
{
|
||||
/* If the message received is 'exit', close the whole server side. */
|
||||
/* 如果接收的是exit,则关闭整个服务端 */
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
goto __exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Show the message in terminal */
|
||||
/* 在控制终端显示收到的数据 */
|
||||
LOG_D("Received data = %s", recv_data);
|
||||
}
|
||||
}
|
||||
/* Send message to connected socket */
|
||||
/* 发送数据到connected socket */
|
||||
ret = send(connected, send_data, rt_strlen(send_data), 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
LOG_E("send error(%d), close the connect.", errno);
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
break;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* Socket has performed an orderly shutdown */
|
||||
/* 连接已断开 */
|
||||
LOG_E("Socket has performed an orderly shutdown.");
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
break;
|
||||
}
|
||||
else if (ret != rt_strlen(send_data))
|
||||
{
|
||||
LOG_W("%d out of %d bytes sent.", ret, rt_strlen(send_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__exit:
|
||||
if (recv_data)
|
||||
{
|
||||
rt_free(recv_data);
|
||||
recv_data = RT_NULL;
|
||||
}
|
||||
if (connected >= 0)
|
||||
{
|
||||
closesocket(connected);
|
||||
connected = -1;
|
||||
}
|
||||
if (sock >= 0)
|
||||
{
|
||||
closesocket(sock);
|
||||
sock = -1;
|
||||
}
|
||||
started = 0;
|
||||
is_running = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The usage description of tcp server on rt-Thread
|
||||
*/
|
||||
static void usage(void)
|
||||
{
|
||||
rt_kprintf("Usage: tcpserver -p <port>\n");
|
||||
rt_kprintf(" tcpserver --stop\n");
|
||||
rt_kprintf(" tcpserver --help\n");
|
||||
rt_kprintf("\n");
|
||||
rt_kprintf("Miscellaneous:\n");
|
||||
rt_kprintf(" -p Specify the host port number\n");
|
||||
rt_kprintf(" --stop Stop tcpserver program\n");
|
||||
rt_kprintf(" --help Print help information\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is for testing tcp server on rt-Thread
|
||||
*/
|
||||
static void tcpserver_test(int argc, char** argv)
|
||||
{
|
||||
rt_thread_t tid;
|
||||
|
||||
if (argc == 1 || argc > 3)
|
||||
{
|
||||
LOG_I("Please check the command you entered!\n");
|
||||
goto __usage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_strcmp(argv[1], "--help") == 0)
|
||||
{
|
||||
goto __usage;
|
||||
}
|
||||
else if (rt_strcmp(argv[1], "--stop") == 0)
|
||||
{
|
||||
is_running = 0;
|
||||
return;
|
||||
}
|
||||
else if (rt_strcmp(argv[1], "-p") == 0)
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
LOG_I("The tcpserver has started!");
|
||||
LOG_I("Please stop tcpserver firstly, by: tcpserver --stop");
|
||||
return;
|
||||
}
|
||||
|
||||
port = atoi(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto __usage;
|
||||
}
|
||||
}
|
||||
|
||||
tid = rt_thread_create("tcp_serv",
|
||||
tcpserv, RT_NULL,
|
||||
2048, RT_THREAD_PRIORITY_MAX/3, 20);
|
||||
if (tid != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(tid);
|
||||
}
|
||||
return;
|
||||
|
||||
__usage:
|
||||
usage();
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
MSH_CMD_EXPORT_ALIAS(tcpserver_test, tcpserver,
|
||||
Start a tcp server. Help: tcpserver --help);
|
||||
#endif
|
||||
182
RT_Thread/examples/network/udpclient.c
Normal file
182
RT_Thread/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
RT_Thread/examples/network/udpserver.c
Normal file
214
RT_Thread/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
RT_Thread/examples/pm/timer_app.c
Normal file
55
RT_Thread/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
RT_Thread/examples/pm/wakeup_app.c
Normal file
77
RT_Thread/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
RT_Thread/examples/rt-link/rtlink_dev_example.c
Normal file
400
RT_Thread/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
RT_Thread/examples/rt-link/rtlink_example.c
Normal file
214
RT_Thread/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
RT_Thread/examples/test/avl.c
Normal file
585
RT_Thread/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)
|
||||
{
|
||||
rt_sscanf(argv[1], "%d", &loop_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
loop_count = 1000;
|
||||
}
|
||||
|
||||
puts("Benchmark");
|
||||
printf("looping times: %d\n", loop_count);
|
||||
|
||||
init_test();
|
||||
int endurance;
|
||||
STOPWATCH(insert_test, endurance);
|
||||
printf("Insertion: %d ms\n", endurance);
|
||||
|
||||
randomize(dataset, loop_count);
|
||||
STOPWATCH(search_test, endurance);
|
||||
printf("Search: %d ms\n", endurance);
|
||||
|
||||
randomize(dataset, loop_count);
|
||||
STOPWATCH(delete_test, endurance);
|
||||
printf("Delete: %d ms\n", endurance);
|
||||
|
||||
cleanup();
|
||||
puts("Benchmark exit");
|
||||
return 0;
|
||||
}
|
||||
516
RT_Thread/examples/test/device_test.c
Normal file
516
RT_Thread/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
RT_Thread/examples/test/dhry.h
Normal file
412
RT_Thread/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
RT_Thread/examples/test/dhry_1.c
Normal file
349
RT_Thread/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
RT_Thread/examples/test/dhry_2.c
Normal file
192
RT_Thread/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
RT_Thread/examples/test/fs_test.c
Normal file
297
RT_Thread/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
RT_Thread/examples/test/hwtimer_test.c
Normal file
111
RT_Thread/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
RT_Thread/examples/test/mem_test.c
Normal file
114
RT_Thread/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
RT_Thread/examples/test/net_test.c
Normal file
345
RT_Thread/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
RT_Thread/examples/test/rbb_test.c
Normal file
327
RT_Thread/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
RT_Thread/examples/test/ringbuffer_test.c
Normal file
106
RT_Thread/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
RT_Thread/examples/test/rtc_test.c
Normal file
61
RT_Thread/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
RT_Thread/examples/ulog/ulog_example.c
Normal file
93
RT_Thread/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
RT_Thread/examples/utest/README.md
Normal file
73
RT_Thread/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
RT_Thread/examples/utest/configs/cpp11/cpp11.conf
Normal file
4
RT_Thread/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
RT_Thread/examples/utest/configs/kernel/atomic.conf
Normal file
4
RT_Thread/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
RT_Thread/examples/utest/configs/kernel/atomic_c11.conf
Normal file
5
RT_Thread/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
|
||||
4
RT_Thread/examples/utest/configs/kernel/device.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/device.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_DEVICE_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
||||
14
RT_Thread/examples/utest/configs/kernel/ipc.conf
Normal file
14
RT_Thread/examples/utest/configs/kernel/ipc.conf
Normal file
@ -0,0 +1,14 @@
|
||||
CONFIG_UTEST_SEMAPHORE_TC=y
|
||||
CONFIG_UTEST_EVENT_TC=y
|
||||
CONFIG_UTEST_MESSAGEQUEUE_TC=y
|
||||
CONFIG_UTEST_SIGNAL_TC=y
|
||||
CONFIG_UTEST_MUTEX_TC=y
|
||||
CONFIG_UTEST_MAILBOX_TC=y
|
||||
CONFIG_UTEST_WORKQUEUE_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_SEMAPHORE=y
|
||||
CONFIG_RT_USING_EVENT=y
|
||||
CONFIG_RT_USING_MESSAGEQUEUE=y
|
||||
CONFIG_RT_USING_SIGNALS=y
|
||||
CONFIG_RT_USING_MUTEX=y
|
||||
CONFIG_RT_USING_MAILBOX=y
|
||||
3
RT_Thread/examples/utest/configs/kernel/irq.conf
Normal file
3
RT_Thread/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
RT_Thread/examples/utest/configs/kernel/mem.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/mem.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
||||
4
RT_Thread/examples/utest/configs/kernel/thread.conf
Normal file
4
RT_Thread/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
RT_Thread/examples/utest/configs/kernel/timer.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/timer.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_TIMER_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
6
RT_Thread/examples/utest/configs/rtsmart/base.conf
Normal file
6
RT_Thread/examples/utest/configs/rtsmart/base.conf
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_SMART=y
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
||||
CONFIG_RT_USING_DFS_V2=y
|
||||
1
RT_Thread/examples/utest/configs/utest_self/self.conf
Normal file
1
RT_Thread/examples/utest/configs/utest_self/self.conf
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_UTEST_SELF_PASS_TC=y
|
||||
22
RT_Thread/examples/utest/testcases/Kconfig
Normal file
22
RT_Thread/examples/utest/testcases/Kconfig
Normal file
@ -0,0 +1,22 @@
|
||||
menu "RT-Thread Utestcases"
|
||||
|
||||
config RT_USING_UTESTCASES
|
||||
bool "RT-Thread Utestcases"
|
||||
default n
|
||||
select RT_USING_UTEST
|
||||
|
||||
if RT_USING_UTESTCASES
|
||||
|
||||
rsource "utest/Kconfig"
|
||||
rsource "kernel/Kconfig"
|
||||
rsource "cpp11/Kconfig"
|
||||
rsource "drivers/serial_v2/Kconfig"
|
||||
rsource "drivers/serial_bypass/Kconfig"
|
||||
rsource "drivers/ipc/Kconfig"
|
||||
rsource "posix/Kconfig"
|
||||
rsource "mm/Kconfig"
|
||||
rsource "tmpfs/Kconfig"
|
||||
rsource "smp_call/Kconfig"
|
||||
endif
|
||||
|
||||
endmenu
|
||||
15
RT_Thread/examples/utest/testcases/SConscript
Normal file
15
RT_Thread/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
RT_Thread/examples/utest/testcases/cpp11/Kconfig
Normal file
9
RT_Thread/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
RT_Thread/examples/utest/testcases/cpp11/SConscript
Normal file
13
RT_Thread/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
RT_Thread/examples/utest/testcases/cpp11/thread_tc.cpp
Normal file
59
RT_Thread/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
RT_Thread/examples/utest/testcases/drivers/SConscript
Normal file
15
RT_Thread/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')
|
||||
11
RT_Thread/examples/utest/testcases/drivers/ipc/Kconfig
Normal file
11
RT_Thread/examples/utest/testcases/drivers/ipc/Kconfig
Normal file
@ -0,0 +1,11 @@
|
||||
menu "Utest IPC Testcase"
|
||||
|
||||
config UTEST_COMPLETION_TC
|
||||
bool "rt_completion testcase"
|
||||
default n
|
||||
|
||||
config UTEST_WORKQUEUE_TC
|
||||
bool "rt_workqueue testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
16
RT_Thread/examples/utest/testcases/drivers/ipc/SConscript
Normal file
16
RT_Thread/examples/utest/testcases/drivers/ipc/SConscript
Normal file
@ -0,0 +1,16 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_COMPLETION_TC']):
|
||||
src += ['completion_tc.c', 'completion_timeout_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_WORKQUEUE_TC']):
|
||||
src += ['workqueue_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
199
RT_Thread/examples/utest/testcases/drivers/ipc/completion_tc.c
Normal file
199
RT_Thread/examples/utest/testcases/drivers/ipc/completion_tc.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-04-30 Shell init ver.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Case for rt_completion API
|
||||
*
|
||||
* The test simulates a producer-consumer interaction where a producer thread
|
||||
* generates data, and a consumer thread consumes the data after waiting for its
|
||||
* availability using rt_completion synchronization primitives.
|
||||
*
|
||||
* Test Criteria:
|
||||
* - The producer should correctly increment the test data and signal
|
||||
* completion.
|
||||
* - The consumer should correctly wait for data update, consume it, and signal
|
||||
* completion.
|
||||
* - Data integrity should be maintained between producer and consumer.
|
||||
* - Synchronization is properly done so both can see consistent data.
|
||||
* - Random latency is introduced to simulate racing scenarios.
|
||||
*/
|
||||
|
||||
#define TEST_LATENCY_TICK (1)
|
||||
#define TEST_LOOP_TIMES (60 * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_ON (RT_TICK_PER_SECOND)
|
||||
|
||||
#include "utest.h"
|
||||
|
||||
#include <ipc/completion.h>
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct rt_completion _prod_completion;
|
||||
static struct rt_completion _cons_completion;
|
||||
static int _test_data = 0;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
|
||||
static void done_safely(struct rt_completion *completion)
|
||||
{
|
||||
rt_err_t error;
|
||||
|
||||
/* Signal completion */
|
||||
error = rt_completion_wakeup(completion);
|
||||
|
||||
/* try again if failed to produce */
|
||||
if (error == -RT_EEMPTY)
|
||||
{
|
||||
rt_thread_yield();
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
uassert_false(0);
|
||||
rt_thread_delete(rt_thread_self());
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_safely(struct rt_completion *completion)
|
||||
{
|
||||
rt_err_t error;
|
||||
do
|
||||
{
|
||||
error = rt_completion_wait_flags(completion, RT_WAITING_FOREVER,
|
||||
RT_INTERRUPTIBLE);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(error == -RT_EINTR);
|
||||
rt_thread_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static void producer_thread_entry(void *parameter)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* Produce data */
|
||||
_test_data++;
|
||||
|
||||
/* notify consumer */
|
||||
done_safely(&_prod_completion);
|
||||
|
||||
/* Delay before producing next data */
|
||||
rt_thread_delay(TEST_LATENCY_TICK);
|
||||
|
||||
/* sync with consumer */
|
||||
wait_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void _wait_until_edge(void)
|
||||
{
|
||||
rt_tick_t entry_level, current;
|
||||
rt_base_t random_latency;
|
||||
|
||||
entry_level = rt_tick_get();
|
||||
do
|
||||
{
|
||||
current = rt_tick_get();
|
||||
} while (current == entry_level);
|
||||
|
||||
/* give a random latency for test */
|
||||
random_latency = rand();
|
||||
entry_level = current;
|
||||
for (size_t i = 0; i < random_latency; i++)
|
||||
{
|
||||
current = rt_tick_get();
|
||||
if (current != entry_level) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void consumer_thread_entry(void *parameter)
|
||||
{
|
||||
int local_test_data = 0;
|
||||
|
||||
rt_thread_startup(parameter);
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* add more random case for test */
|
||||
_wait_until_edge();
|
||||
|
||||
/* Wait for data update */
|
||||
wait_safely(&_prod_completion);
|
||||
|
||||
/* Consume data */
|
||||
if (local_test_data + 1 != _test_data)
|
||||
{
|
||||
LOG_I("local test data is %d, shared test data is %d",
|
||||
local_test_data, _test_data);
|
||||
uassert_true(0);
|
||||
}
|
||||
else if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
{
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
local_test_data = _test_data;
|
||||
done_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* Initialize completion object */
|
||||
rt_completion_init(&_prod_completion);
|
||||
rt_completion_init(&_cons_completion);
|
||||
|
||||
/* Create producer and consumer threads */
|
||||
rt_thread_t producer_thread =
|
||||
rt_thread_create("producer", producer_thread_entry, RT_NULL,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
rt_thread_t consumer_thread =
|
||||
rt_thread_create("consumer", consumer_thread_entry, producer_thread,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
uassert_true(producer_thread != RT_NULL);
|
||||
uassert_true(consumer_thread != RT_NULL);
|
||||
|
||||
LOG_I("Summary:\n"
|
||||
"\tTest times: %ds(%d)",
|
||||
TEST_LOOP_TIMES / RT_TICK_PER_SECOND, TEST_LOOP_TIMES);
|
||||
|
||||
rt_thread_startup(consumer_thread);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_test_data = 0;
|
||||
_progress_counter = 0;
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.ipc.rt_completion.basic",
|
||||
utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-04-30 Shell init ver.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Case for rt_completion API
|
||||
*
|
||||
* The test simulates a producer-consumer interaction where a producer thread
|
||||
* generates data, and a consumer thread consumes the data after waiting for its
|
||||
* availability using rt_completion synchronization primitives.
|
||||
*
|
||||
* Test Criteria:
|
||||
* - The producer produces data correctly and notifies the consumer thread.
|
||||
* - The consumer receives data correctly and acknowledges receipt to the
|
||||
* producer.
|
||||
* - The producer and consumer threads synchronize their operations effectively.
|
||||
* - Verify the correctness of data production and consumption between producer
|
||||
* and consumer threads.
|
||||
* - The asynchronous woken of consumer thread was handled properly so the
|
||||
* consumer don't lose woken from producer.
|
||||
*
|
||||
* Test APIs:
|
||||
* - rt_completion_init()
|
||||
* - rt_completion_wakeup()
|
||||
* - rt_completion_wait_flags()
|
||||
*/
|
||||
|
||||
#define TEST_LATENCY_TICK (1)
|
||||
#define TEST_LOOP_TIMES (60 * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_ON (RT_TICK_PER_SECOND)
|
||||
|
||||
#include "utest.h"
|
||||
|
||||
#include <ipc/completion.h>
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct rt_completion _prod_completion;
|
||||
static struct rt_completion _cons_completion;
|
||||
static int _test_data;
|
||||
static int _async_intr_count;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
|
||||
static void _test_thread_exit_failure(char *string)
|
||||
{
|
||||
LOG_E("\t[TEST failed] %s", string);
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
rt_thread_delete(rt_thread_self());
|
||||
}
|
||||
|
||||
static void done_safely(struct rt_completion *completion)
|
||||
{
|
||||
rt_err_t error;
|
||||
|
||||
/* Signal completion */
|
||||
error = rt_completion_wakeup(completion);
|
||||
|
||||
/* try again if failed to produce */
|
||||
if (error == -RT_EEMPTY)
|
||||
{
|
||||
rt_thread_yield();
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
uassert_true(error == RT_EOK);
|
||||
_test_thread_exit_failure("unexpected error");
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_safely(struct rt_completion *completion)
|
||||
{
|
||||
int try_times = 3;
|
||||
rt_err_t error;
|
||||
do
|
||||
{
|
||||
/* wait for one tick, to add more random */
|
||||
error = rt_completion_wait_flags(completion, 1, RT_INTERRUPTIBLE);
|
||||
if (error)
|
||||
{
|
||||
if (error == -RT_ETIMEOUT || error == -RT_EINTR)
|
||||
{
|
||||
_async_intr_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("Async event %d\n", error);
|
||||
uassert_true(0);
|
||||
}
|
||||
rt_thread_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (try_times--);
|
||||
|
||||
if (error != RT_EOK)
|
||||
{
|
||||
uassert_true(error == RT_EOK);
|
||||
_test_thread_exit_failure("wait failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void producer_thread_entry(void *parameter)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* Produce data */
|
||||
_test_data++;
|
||||
|
||||
/* Delay before producing next data */
|
||||
rt_thread_delay(TEST_LATENCY_TICK);
|
||||
|
||||
/* notify consumer */
|
||||
done_safely(&_prod_completion);
|
||||
|
||||
/* sync with consumer */
|
||||
wait_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void consumer_thread_entry(void *parameter)
|
||||
{
|
||||
int local_test_data = 0;
|
||||
|
||||
rt_thread_startup(parameter);
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* Wait for data update */
|
||||
wait_safely(&_prod_completion);
|
||||
|
||||
/* Consume data */
|
||||
if (local_test_data + 1 != _test_data)
|
||||
{
|
||||
LOG_I("local test data is %d, shared test data is %d",
|
||||
local_test_data, _test_data);
|
||||
uassert_true(0);
|
||||
}
|
||||
else if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
{
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
local_test_data = _test_data;
|
||||
done_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
rt_thread_t _watching_thread1;
|
||||
rt_thread_t _watching_thread2;
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* Initialize completion object */
|
||||
rt_completion_init(&_prod_completion);
|
||||
rt_completion_init(&_cons_completion);
|
||||
|
||||
/* Create producer and consumer threads */
|
||||
rt_thread_t producer_thread =
|
||||
rt_thread_create("producer", producer_thread_entry, RT_NULL,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
rt_thread_t consumer_thread =
|
||||
rt_thread_create("consumer", consumer_thread_entry, producer_thread,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
uassert_true(producer_thread != RT_NULL);
|
||||
uassert_true(consumer_thread != RT_NULL);
|
||||
_watching_thread1 = consumer_thread;
|
||||
_watching_thread2 = producer_thread;
|
||||
|
||||
rt_thread_startup(consumer_thread);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
LOG_I("Summary:\n"
|
||||
"\tTest times: %ds(%d times)\n"
|
||||
"\tAsync interruption count: %d\n",
|
||||
TEST_LOOP_TIMES / RT_TICK_PER_SECOND, TEST_LOOP_TIMES,
|
||||
_async_intr_count);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_test_data = 0;
|
||||
_progress_counter = 0;
|
||||
_async_intr_count = 0;
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.ipc.rt_completion.timeout",
|
||||
utest_tc_init, utest_tc_cleanup, 1000);
|
||||
603
RT_Thread/examples/utest/testcases/drivers/ipc/workqueue_tc.c
Normal file
603
RT_Thread/examples/utest/testcases/drivers/ipc/workqueue_tc.c
Normal file
@ -0,0 +1,603 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-06 tyx first commit
|
||||
* 2024-12-31 rbb666 Adding Test Cases
|
||||
*/
|
||||
|
||||
#include "rtthread.h"
|
||||
#include "rtdevice.h"
|
||||
#include "utest.h"
|
||||
|
||||
#ifdef RT_USING_DEVICE_IPC
|
||||
|
||||
static rt_uint8_t get_test_thread_priority(rt_int8_t pos)
|
||||
{
|
||||
rt_int16_t priority;
|
||||
|
||||
priority = RT_SCHED_PRIV(rt_thread_self()).init_priority;
|
||||
if (pos == 0)
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority += pos;
|
||||
}
|
||||
if (priority < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (priority >= RT_THREAD_PRIORITY_MAX)
|
||||
{
|
||||
return RT_THREAD_PRIORITY_MAX - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (rt_uint8_t)priority;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_work_test_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void do_work_test(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 higher priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, do_work_test_fun, (void *)&work_flag);
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Delay 5 ticks to ensure that the task has been executed */
|
||||
rt_thread_delay(5);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void do_delay_work_test_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((rt_tick_t *)work_data) = rt_tick_get();
|
||||
}
|
||||
|
||||
static void do_delay_work_test(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile rt_tick_t work_start = 0;
|
||||
volatile rt_tick_t work_end = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 higher priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, do_delay_work_test_fun, (void *)&work_end);
|
||||
work_start = rt_tick_get();
|
||||
/* Normal delayed work submission test */
|
||||
err = rt_workqueue_submit_work(queue, &work, 10);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Ensure that the delayed work has been executed */
|
||||
rt_thread_delay(15);
|
||||
/* Check if the delayed task is executed after 10 ticks */
|
||||
if (work_end < work_start || work_end - work_start < 10)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void cancle_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, cancle_work_test01_fun, (void *)&work_flag);
|
||||
/* Cancel the work before it is executed */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Cancel Now */
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test02_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
}
|
||||
|
||||
static void cancle_work_test02(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 higher priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, cancle_work_test02_fun, RT_NULL);
|
||||
/* Cancel the work while it is in progress */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, -RT_EBUSY);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test03_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
|
||||
static void cancle_work_test03(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, cancle_work_test03_fun, RT_NULL);
|
||||
/* Canceling a work after it has been executed */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(10);
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test04_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void cancle_work_test04(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, cancle_work_test04_fun, (void *)&work_flag);
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
/* Synchronized cancellation work */
|
||||
err = rt_workqueue_cancel_work_sync(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_delay_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void cancle_delay_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, cancle_delay_work_test01_fun, (void *)&work_flag);
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(10);
|
||||
/* Cancel work */
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(15);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void repeat_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test01", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, repeat_work_test01_fun, (void *)&work_flag);
|
||||
/* Multiple submissions of the same work */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* The same work, before it is executed, can be submitted repeatedly and executed only once */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
LOG_E("L:%d err. %d", __LINE__, err);
|
||||
}
|
||||
rt_thread_delay(10);
|
||||
/* Check if it was executed only once */
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void repeat_work_test02_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_work_test02(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 priority higher than current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test02", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, repeat_work_test02_fun, (void *)&work_flag);
|
||||
/* Submit work with high queue priority that will be executed immediately */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
/* Re-submission of work in progress */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
LOG_E("L:%d err. %d", __LINE__, err);
|
||||
}
|
||||
rt_thread_delay(10);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(10);
|
||||
uassert_int_equal(work_flag, 2);
|
||||
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static struct rt_workqueue *queue_3;
|
||||
|
||||
static void repeat_work_test03_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
int *work_flag = (int *)work_data;
|
||||
(*work_flag) += 1;
|
||||
rt_kprintf("work_flag:%d\n", *work_flag);
|
||||
if (*work_flag < 20)
|
||||
{
|
||||
rt_workqueue_submit_work(queue_3, work, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void repeat_work_test03(void)
|
||||
{
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 priority higher than current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue_3 = rt_workqueue_create("test03", 2048, curr_priority);
|
||||
if (queue_3 == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, repeat_work_test03_fun, (void *)&work_flag);
|
||||
/* Submit work with high queue priority that will be executed immediately */
|
||||
err = rt_workqueue_submit_work(queue_3, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Wait for the work to be executed 20 times with a timeout */
|
||||
err = rt_workqueue_cancel_work_sync(queue_3, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Check if the work was executed 20 times */
|
||||
uassert_int_equal(work_flag, 20);
|
||||
|
||||
rt_workqueue_destroy(queue_3);
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, repeat_delay_work_test01_fun, (void *)&work_flag);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* At this point the delayed work has not been executed */
|
||||
rt_thread_delay(10);
|
||||
/* Re-submission of time-delayed work */
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(15);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
/* Waiting for delayed task execution */
|
||||
rt_thread_delay(15);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test02_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test02(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, repeat_delay_work_test02_fun, (void *)&work_flag);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Waiting for delayed work execution */
|
||||
rt_thread_delay(25);
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Check if the delayed work has been run only once */
|
||||
rt_thread_delay(10);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(25);
|
||||
/* Check if the delayed work is executed twice */
|
||||
uassert_int_equal(work_flag, 2);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancel_all_work_test_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void cancel_all_work_test(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work1;
|
||||
struct rt_work work2;
|
||||
struct rt_work work3;
|
||||
struct rt_work work4;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work1, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
rt_work_init(&work2, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
rt_work_init(&work3, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
rt_work_init(&work4, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work1, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work2, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work3, 10);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work4, 10);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_cancel_all_work(queue);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(20);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* General work queue test */
|
||||
UTEST_UNIT_RUN(do_work_test);
|
||||
/* Delayed work queue test */
|
||||
UTEST_UNIT_RUN(do_delay_work_test);
|
||||
/* Cancellation of work prior to implementation */
|
||||
UTEST_UNIT_RUN(cancle_work_test01);
|
||||
/* Cancellation of work during execution */
|
||||
UTEST_UNIT_RUN(cancle_work_test02);
|
||||
/* Cancellation of work after implementation */
|
||||
UTEST_UNIT_RUN(cancle_work_test03);
|
||||
/* Synchronized cancellation of work during execution */
|
||||
UTEST_UNIT_RUN(cancle_work_test04);
|
||||
/* Cancel delayed work before execution */
|
||||
UTEST_UNIT_RUN(cancle_delay_work_test01);
|
||||
/* Multiple submissions of the same work prior to implementation */
|
||||
UTEST_UNIT_RUN(repeat_work_test01);
|
||||
/* Multiple submissions of the same work during execution */
|
||||
UTEST_UNIT_RUN(repeat_work_test02);
|
||||
/* Submitting the same task multiple times in a mission */
|
||||
UTEST_UNIT_RUN(repeat_work_test03);
|
||||
/* Multiple submissions of the same delayed task before execution */
|
||||
UTEST_UNIT_RUN(repeat_delay_work_test01);
|
||||
/* Multiple submissions of the same delayed task during execution */
|
||||
UTEST_UNIT_RUN(repeat_delay_work_test02);
|
||||
/* Cancel all works */
|
||||
UTEST_UNIT_RUN(cancel_all_work_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "components.drivers.ipc.workqueue_tc", utest_tc_init, utest_tc_cleanup, 300);
|
||||
#endif
|
||||
@ -0,0 +1,7 @@
|
||||
menu "Serial-Bypass Testcase"
|
||||
|
||||
config UTEST_SERIAL_BYPASS
|
||||
bool "Serial testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
@ -0,0 +1,11 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('bypass*.c')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_BYPASS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static struct rt_spinlock lock;
|
||||
static int cnt = 0;
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
|
||||
#define UART_FR(base) __REG32(base + 0x18)
|
||||
#define UART_DR(base) __REG32(base + 0x00)
|
||||
#define UARTFR_TXFF 0x20
|
||||
|
||||
static rt_err_t utest_get_c(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
rt_atomic_add(&cnt, 1);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc(struct rt_serial_device* serial)
|
||||
{
|
||||
static int num = 0;
|
||||
|
||||
rt_spin_lock(&lock);
|
||||
if (rt_atomic_load(&num) == 10)
|
||||
{
|
||||
rt_atomic_flag_clear(&num);
|
||||
rt_spin_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
rt_atomic_add(&num, 1);
|
||||
rt_spin_unlock(&lock);
|
||||
return 'a';
|
||||
}
|
||||
|
||||
struct hw_uart_device
|
||||
{
|
||||
rt_size_t hw_base;
|
||||
rt_size_t irqno;
|
||||
};
|
||||
|
||||
static int uart_putc(struct rt_serial_device* serial, char c)
|
||||
{
|
||||
struct hw_uart_device* uart;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct hw_uart_device*)serial->parent.user_data;
|
||||
|
||||
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
|
||||
UART_DR(uart->hw_base) = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc,
|
||||
};
|
||||
|
||||
|
||||
static void thread_rx1(void* parameter)
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_rx2(void* parameter)
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
rt_workqueue_dowork(_serial0->bypass->lower_workq, &_serial0->bypass->work);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_high_priority(void* parameter)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_get_c, RT_NULL);
|
||||
rt_bypass_upper_unregister(_serial0, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_low_priority(void* parameter)
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
}
|
||||
|
||||
static void bypass_rx_stress_003(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
|
||||
rt_thread_t high = rt_thread_create("high_prio", thread_high_priority, RT_NULL, 2048, 15, 10);
|
||||
rt_thread_t low = rt_thread_create("low_prio", thread_low_priority, RT_NULL, 2048, 20, 10);
|
||||
|
||||
rt_atomic_flag_clear(&cnt);
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_upper_register(_serial0, "test", 0, utest_get_c, RT_NULL);
|
||||
|
||||
rt_thread_startup(high);
|
||||
rt_thread_startup(low);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, 0);
|
||||
uassert_true(rt_atomic_load(&cnt) == 200);
|
||||
}
|
||||
|
||||
static void bypass_rx_stress_002(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
rt_thread_t rx2 = rt_thread_create("rx2", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_thread_t rx3 = rt_thread_create("rx3", thread_rx2, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
|
||||
rt_atomic_flag_clear(&cnt);
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_lower_register(_serial0, "utest", 0, utest_get_c, RT_NULL);
|
||||
|
||||
rt_thread_startup(rx2);
|
||||
rt_thread_startup(rx3);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
uassert_true(rt_atomic_load(&cnt) == 100);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_lower_unregister(_serial0, 0);
|
||||
}
|
||||
|
||||
static void bypass_rx_stress_001(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
rt_thread_t rx1 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_thread_t rx2 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
|
||||
cnt = 0;
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_upper_register(_serial0, "utest", 0, utest_get_c, RT_NULL);
|
||||
|
||||
rt_thread_startup(rx1);
|
||||
rt_thread_startup(rx2);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
uassert_true(rt_atomic_load(&cnt) == 200);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, 0);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_rx_stress_001);
|
||||
UTEST_UNIT_RUN(bypass_rx_stress_002);
|
||||
UTEST_UNIT_RUN(bypass_rx_stress_003);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.conflict.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static int cnt = 0;
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
|
||||
#define UART_FR(base) __REG32(base + 0x18)
|
||||
#define UART_DR(base) __REG32(base + 0x00)
|
||||
#define UARTFR_TXFF 0x20
|
||||
|
||||
struct hw_uart_device
|
||||
{
|
||||
rt_size_t hw_base;
|
||||
rt_size_t irqno;
|
||||
};
|
||||
|
||||
static int uart_putc(struct rt_serial_device* serial, char c)
|
||||
{
|
||||
struct hw_uart_device* uart;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct hw_uart_device*)serial->parent.user_data;
|
||||
|
||||
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
|
||||
UART_DR(uart->hw_base) = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
num++;
|
||||
uassert_true(ch == ('a' + num));
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc_2(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 20)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a' + num;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops2 =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc_2,
|
||||
};
|
||||
|
||||
static rt_err_t utest_lower_run(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
uassert_true(ch == 'a');
|
||||
cnt++;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
static int utest_getc(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 10)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a';
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc,
|
||||
};
|
||||
static void bypass_lower_001(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run, RT_NULL);
|
||||
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
|
||||
}
|
||||
|
||||
static void bypass_lower_002(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops2;
|
||||
rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL);
|
||||
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_lower_001);
|
||||
UTEST_UNIT_RUN(bypass_lower_002);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.lower.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static struct rt_spinlock lock;
|
||||
|
||||
static rt_err_t utest_001_run(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thread_serial_register1(void* parameter)
|
||||
{
|
||||
for (int i = 2; i < 10; i += 2)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_serial_register_upper(void* parameter)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_serial_register_lower(void* parameter)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
rt_bypass_lower_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void bypass_register_001(void)
|
||||
{
|
||||
rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL);
|
||||
rt_thread_startup(t1);
|
||||
for (int i = 1; i < 10; i += 2)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
rt_thread_mdelay(1000);
|
||||
rt_list_t* node = _serial0->bypass->upper_h->head.next;
|
||||
for (int i = 0; i < 10;i++)
|
||||
{
|
||||
rt_list_t* next = node->next;
|
||||
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
|
||||
uassert_true(temp->level == i);
|
||||
rt_bypass_upper_unregister(_serial0, temp->level);
|
||||
node = next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void bypass_register_002(void)
|
||||
{
|
||||
rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register_upper, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_thread_t t2 = rt_thread_create("serial_register", thread_serial_register_lower, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL);
|
||||
|
||||
rt_thread_startup(t1);
|
||||
rt_thread_startup(t2);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
rt_list_t* node = _serial0->bypass->upper_h->head.next;
|
||||
for (int i = 0; i < 10;i++)
|
||||
{
|
||||
rt_list_t* next = node->next;
|
||||
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
|
||||
uassert_true(temp->level == i);
|
||||
rt_bypass_upper_unregister(_serial0, temp->level);
|
||||
node = next;
|
||||
}
|
||||
node = _serial0->bypass->lower_h->head.next;
|
||||
for (int i = 1; i < 10;i++)
|
||||
{
|
||||
rt_list_t* next = node->next;
|
||||
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
|
||||
uassert_true(temp->level == i);
|
||||
rt_bypass_lower_unregister(_serial0, temp->level);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_register_001);
|
||||
UTEST_UNIT_RUN(bypass_register_002);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.register.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static int cnt;
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
|
||||
#define UART_FR(base) __REG32(base + 0x18)
|
||||
#define UART_DR(base) __REG32(base + 0x00)
|
||||
#define UARTFR_TXFF 0x20
|
||||
static rt_err_t utest_upper_run(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
uassert_true(ch == 'a');
|
||||
cnt++;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 10)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a';
|
||||
}
|
||||
|
||||
struct hw_uart_device
|
||||
{
|
||||
rt_size_t hw_base;
|
||||
rt_size_t irqno;
|
||||
};
|
||||
|
||||
static int uart_putc(struct rt_serial_device* serial, char c)
|
||||
{
|
||||
struct hw_uart_device* uart;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct hw_uart_device*)serial->parent.user_data;
|
||||
|
||||
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
|
||||
UART_DR(uart->hw_base) = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc,
|
||||
};
|
||||
|
||||
static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
num++;
|
||||
uassert_true(ch == ('a' + num));
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc_2(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 20)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a' + num;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops2 =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc_2,
|
||||
};
|
||||
static void bypass_upper_001(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_LEVEL_1, utest_upper_run, RT_NULL);
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, RT_BYPASS_LEVEL_1);
|
||||
}
|
||||
|
||||
static void bypass_upper_002(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops2;
|
||||
rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL);
|
||||
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_upper_001);
|
||||
UTEST_UNIT_RUN(bypass_upper_002);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.upper.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,7 @@
|
||||
menu "Utest Serial Testcase"
|
||||
|
||||
config UTEST_SERIAL_TC
|
||||
bool "Serial testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
158
RT_Thread/examples/utest/testcases/drivers/serial_v2/README.md
Normal file
158
RT_Thread/examples/utest/testcases/drivers/serial_v2/README.md
Normal file
@ -0,0 +1,158 @@
|
||||
## 1、介绍
|
||||
|
||||
该目录下 c 文件是新版本串口的测试用例,在 `examples/utest/testcases/drivers/serial_v2` 目录结构里,该测试用例用来测试串口的各个操作模式是否正常工作。
|
||||
|
||||
## 2、 文件说明
|
||||
|
||||
| 文件 | 描述 |
|
||||
| ---------------- | ----------------------------------------- |
|
||||
| uart_rxb_txb.c | 串口接收阻塞和发送阻塞模式 的测试用例 |
|
||||
| uart_rxb_txnb.c | 串口接收阻塞和发送非阻塞模式 的测试用例 |
|
||||
| uart_rxnb_txb.c | 串口接收非阻塞和发送阻塞模式 的测试用例 |
|
||||
| uart_rxnb_txnb.c | 串口接收非阻塞和发送非阻塞模式 的测试用例 |
|
||||
| uart_blocking_tx.c| 串口阻塞发送模式 的测试 |
|
||||
| uart_blocking_rx.c| 串口阻塞接收模式 的测试 |
|
||||
| uart_nonblocking_tx.c| 串口非阻塞发送模式 的测试 |
|
||||
| uart_nonblocking_rx.c | 串口非阻塞接收模式 的测试 |
|
||||
|
||||
## 3、软硬件环境
|
||||
|
||||
硬件上需要支持 RT-Thread 的完整版操作系统,版本为4.0.4及以上,且硬件有串口硬件外设,软件上需要支持 内核接口、IPC 、Device 框架。
|
||||
|
||||
## 4、测试项
|
||||
|
||||
### 4.1 测试说明
|
||||
|
||||
上文所提及的模式是指串口使用时的操作模式,不涉及硬件的工作模式的配置情况(硬件工作模式一般有轮询POLL、中断INT、DMA),因此使用时需要结合具体的硬件工作模式去配置使用。例如 发送阻塞和接收非阻塞模式 ,这个测试有很多种硬件配置,配置情况例如:DMA发送阻塞和DMA接收非阻塞,INT发送阻塞和DMA接收非阻塞,POLL发送阻塞和DMA接收非阻塞等等。因此通过排列组合后的测试场景有4*9=36种,有意义的组合方式为20种。如下表:
|
||||
|
||||
|
||||
| 接收非阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 |
|
||||
| ---------- | -------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | ✔ |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | ✔ |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
| 接收非阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 |
|
||||
| ---------- | ---------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
| 接收阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 |
|
||||
| -------- | -------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | ✔ |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | ✔ |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
| 接收阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 |
|
||||
| -------- | ---------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
需要解释的是,为什么会存在无意义的组合模式,举个例子,非阻塞模式下,肯定是不会出现POLL(轮询)方式的,因为POLL方式已经表明是阻塞方式了。
|
||||
该测试用例在测试多种组合时,需要通过更改`rtconfig.h`文件对硬件模式进行静态配置。
|
||||
|
||||
### 4.2 测试思路
|
||||
|
||||
前四个测试用例的测试思路:
|
||||
|
||||
>硬件上:**短接串口的发送TX引脚和接收RX引脚,完成自发自收的回路**。
|
||||
>
|
||||
>软件上:创建两个线程A和B,A为接收线程,B为发送线程,设置A线程优先级比B线程优先级高。发送线程发送随机长度(长度范围是 0 到 1000)的数据,接收线程接收到数据进行校验,数据正确则测试通过,默认测试100次。
|
||||
|
||||
后四个测试用例的测试思路:
|
||||
|
||||
>硬件上: **不需要将TX,RX引脚进行短接**,每次只针对发送或接收中的一种进行测试,更为简单与直接
|
||||
>
|
||||
>软件上: 四个样例每次仅测试TX/RX中的一种引脚与一种对应的阻塞/非阻塞模式
|
||||
>四种测试模式具体分为:
|
||||
>>阻塞接收模式----(硬件工作模式可选: 轮询, 中断, DMA)
|
||||
>>阻塞发送模式----(硬件工作模式可选: 轮询, 中断, DMA)
|
||||
>>非阻塞接收模式--(硬件工作模式可选: 中断, DMA)
|
||||
>>非阻塞发送模式--(硬件工作模式可选: 中断, DMA)
|
||||
>
|
||||
>其中阻塞或非阻塞背后的具体硬件工作模式选择(如 轮询, 中断, DMA)需要对`rtconfig.h`文件做出配置,具体配置流程可见文章中关于
|
||||
[seril_v2硬件工作模式的选择](https://club.rt-thread.org/ask/article/b4c536303c8e2335.html "serial_v2源码分析")一节.
|
||||
>
|
||||
>发送测试流程 :
|
||||
>>1. 先关闭串口,再以需要测试的模式打开.
|
||||
>>2. 然后依次发送 UART_SEND_TIMES(默认为400) * 1024, 8, 32, 128, 512, 1024个数据.
|
||||
>>3. 发送的同时记录每次发送所耗费的时钟周期与成功发送的数据数量.
|
||||
>>3. 打印记录的数据,通过时钟周期来反应发送效率, 通过成功发送的数据量来反应是否产生丢包问题.
|
||||
>
|
||||
>接收测试流程 :
|
||||
>>1. 先关闭串口,再以需要测试的模式打开.
|
||||
>>2. 然后以此接收 256, 256, 256, 128, 128, 共计1024个数据
|
||||
>>3. 接收的同时记录成功接收的数据数量
|
||||
>>4. 打印记录的数据, 通过现实成功接收的数据量与串口发送的数据量做对比,来验证是否出现丢包问题
|
||||
|
||||
## 5、配置
|
||||
|
||||
使用该测试用例需要在 `env` 工具的 `menuconfig` 中做相关配置,配置如下所示(使用 RT-Thread-Studio 的配置路径一致 ):
|
||||
|
||||
```
|
||||
RT-Thread Utestcases --->
|
||||
[*] RT-Thread Utestcases --->
|
||||
Utest Serial Testcase --->
|
||||
[*] Serial testcase
|
||||
```
|
||||
|
||||
## 6、使用
|
||||
|
||||
\- 编译下载。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_blocking_tx` 运行串口阻塞发送测试
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_blocking_rx` 运行串口阻塞接收测试
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_nonblocking_tx` 运行串口非阻塞发送测试
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_nonblocking_rx` 运行串口非阻塞接收测试
|
||||
|
||||
如果仅仅配置了 `Serial testcase` 相关的测试用例,则直接输入 `utest_run` 运行即可将上述测试用例按序测试。
|
||||
|
||||
## 7、注意事项
|
||||
|
||||
\- 需配置正确的测试用例。
|
||||
|
||||
\- 如有需要,可开启 ULOG 查看测试用例日志信息。
|
||||
|
||||
\- 需在 MSH 中输入正确的命令行。
|
||||
|
||||
\- 测试用例默认的测试数据长度范围最大为1000字节,如果接收端的缓冲区大小配置为小于1000字节时,那么在测试接收阻塞模式时,将会由于获取不了1000字节长度导致线程持续阻塞(因为测试用例是按 `recv_len` 长度去接收的,而不是按照单字节去接收的),因此建议接收端的缓冲区大小 (对应宏例如为 `BSP_UART2_RX_BUFSIZE`)设置为1024即可;当然也可按需减小测试的最大数据长度。
|
||||
|
||||
\- 该测试用例需要结合硬件具体的工作模式(POLL 、INT、DMA)进行测试,而硬件工作模式只能选择一种,因此需要在 `rtconfig.h` 中对串口相应的宏进行配置,来选择不同的工作模式去进行测试。
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
uart_rxb_txnb.c
|
||||
uart_rxb_txb.c
|
||||
uart_rxnb_txb.c
|
||||
uart_rxnb_txnb.c
|
||||
uart_blocking_rx.c
|
||||
uart_blocking_tx.c
|
||||
uart_nonblocking_rx.c
|
||||
uart_nonblocking_tx.c
|
||||
''')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_TC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@ -0,0 +1,93 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t block_read(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t total_length, recv_length;
|
||||
rt_uint8_t uart_read_buffer[1024], log_buffer[64];
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_RX_BLOCKING);
|
||||
|
||||
rt_sprintf(log_buffer, "\nBLOCKING READ BEGIN, PLEASE SEND SOME DATAS\n");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
total_length = 0;
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read, total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "BLOCKING READ END");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_blocking_rx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (block_read(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_blocking_rx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_blocking_rx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,118 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
#define UART_SEND_TIMES 400
|
||||
#define UART_TEST_NUMBER 6
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t block_write(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t i, wr_sz, index, write_num_array[UART_TEST_NUMBER], total_write_num[UART_TEST_NUMBER];
|
||||
rt_tick_t tick1, tick2, tick_array[UART_TEST_NUMBER];
|
||||
rt_uint8_t uart_write_buffer[1024];
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
uart_write_buffer[i] = '0' + (i % 49);
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
|
||||
LOG_D("\nBLOCKING WRITE BEGIN\n");
|
||||
rt_thread_mdelay(2000);
|
||||
|
||||
index = 0;
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
for(i = 0; i < UART_SEND_TIMES; i++)
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 1024);
|
||||
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = UART_SEND_TIMES * 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 8);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 8;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 32);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 32;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 128);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 128;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 512);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 512;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 1024);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
LOG_D("\nBLOCKING_TX END\n");
|
||||
for(i = 0; i < index; i++)
|
||||
{
|
||||
LOG_D("\nBLOCKING_MODE : write %d / %d bytes in %d ticks\n", write_num_array[i], total_write_num[i], tick_array[i]);
|
||||
rt_thread_mdelay(1000);
|
||||
}
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_blocking_tx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (block_write(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_blocking_tx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_blocking_tx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,107 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t nonblock_read(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t total_length, recv_length;
|
||||
rt_uint8_t uart_read_buffer[1024], log_buffer[64];
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING);
|
||||
|
||||
rt_sprintf(log_buffer, "\nNONBLOCKING READ BEGIN, PLEASE SEND SOME DATAS\n");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
total_length = 0;
|
||||
rt_device_write(uart_dev, 0, "5\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "\nnonblock : %d bytes read, total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "4\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer,"\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev,0,log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "3\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "\nnonblock : %d bytes read, total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev,0,log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "2\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer,"\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "1\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_sprintf(log_buffer, "BLOCKING READ END");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_nonblocking_rx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (nonblock_read(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_nonblocking_rx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_nonblocking_rx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,128 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
#define UART_SEND_TIMES 400
|
||||
#define UART_TEST_NUMBER 6
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t nonblock_write(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t wr_sz = 0, tmp = 0, i, write_num_array[UART_TEST_NUMBER], total_write_num[UART_TEST_NUMBER], index;
|
||||
rt_tick_t tick1, tick2, tick_array[UART_TEST_NUMBER];
|
||||
rt_uint8_t uart_write_buffer[1024];
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
uart_write_buffer[i] = '0' + (i % 50);
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_NON_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING);
|
||||
|
||||
LOG_D("\nNONBLOCKING WRITE BEGIN\n");
|
||||
rt_thread_mdelay(2000);
|
||||
|
||||
index = 0;
|
||||
tmp = 0;
|
||||
tick1 = rt_tick_get();
|
||||
for (i = 0; i < UART_SEND_TIMES; i++)
|
||||
{
|
||||
wr_sz = 0;
|
||||
while(wr_sz < 1024)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 1024-wr_sz);
|
||||
tmp += wr_sz;
|
||||
}
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = UART_SEND_TIMES * 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = tmp;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 8)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 8-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 8;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 32)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 32-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 32;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 128)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 128-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 128;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 512)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 512-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 512;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 1024)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 1024-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
LOG_D("\nNONBLOCKING_TX END\n");
|
||||
for(i = 0; i < index; i++)
|
||||
{
|
||||
LOG_D("\nNONBLOCKING_MODE : write %d / %d bytes in %d ticks\n", write_num_array[i], total_write_num[i], tick_array[i]);
|
||||
rt_thread_mdelay(1000);
|
||||
}
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_nonblocking_tx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (nonblock_write(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_nonblocking_tx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_nonblocking_tx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -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 */
|
||||
@ -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
|
||||
@ -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 */
|
||||
@ -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
|
||||
84
RT_Thread/examples/utest/testcases/kernel/Kconfig
Normal file
84
RT_Thread/examples/utest/testcases/kernel/Kconfig
Normal file
@ -0,0 +1,84 @@
|
||||
menu "Kernel Testcase"
|
||||
|
||||
config UTEST_MEMHEAP_TC
|
||||
bool "memheap stability test"
|
||||
default y
|
||||
depends on RT_USING_MEMHEAP
|
||||
|
||||
config UTEST_SMALL_MEM_TC
|
||||
bool "mem test"
|
||||
default y
|
||||
depends on RT_USING_SMALL_MEM
|
||||
|
||||
config UTEST_SLAB_TC
|
||||
bool "slab test"
|
||||
default n
|
||||
depends on RT_USING_SLAB
|
||||
|
||||
config UTEST_IRQ_TC
|
||||
bool "IRQ test"
|
||||
default n
|
||||
|
||||
config UTEST_SEMAPHORE_TC
|
||||
bool "semaphore test"
|
||||
default n
|
||||
depends on RT_USING_SEMAPHORE
|
||||
|
||||
config UTEST_EVENT_TC
|
||||
bool "event test"
|
||||
default n
|
||||
depends on RT_USING_EVENT
|
||||
|
||||
config UTEST_TIMER_TC
|
||||
bool "timer test"
|
||||
default n
|
||||
|
||||
config UTEST_MESSAGEQUEUE_TC
|
||||
bool "message queue test"
|
||||
default n
|
||||
|
||||
config UTEST_SIGNAL_TC
|
||||
bool "signal test"
|
||||
select RT_USING_SIGNALS
|
||||
default n
|
||||
|
||||
config UTEST_MUTEX_TC
|
||||
bool "mutex test"
|
||||
default n
|
||||
|
||||
config UTEST_MAILBOX_TC
|
||||
bool "mailbox test"
|
||||
default n
|
||||
|
||||
config UTEST_THREAD_TC
|
||||
bool "thread test"
|
||||
default n
|
||||
select RT_USING_TIMER_SOFT
|
||||
select RT_USING_THREAD
|
||||
|
||||
config UTEST_DEVICE_TC
|
||||
bool "device test"
|
||||
default n
|
||||
|
||||
config UTEST_ATOMIC_TC
|
||||
bool "atomic test"
|
||||
default n
|
||||
|
||||
config UTEST_HOOKLIST_TC
|
||||
bool "hook list test"
|
||||
select RT_USING_HOOKLIST
|
||||
default n
|
||||
|
||||
config UTEST_MTSAFE_KPRINT_TC
|
||||
bool "mtsafe kprint test"
|
||||
default n
|
||||
|
||||
config UTEST_SCHEDULER_TC
|
||||
bool "scheduler test"
|
||||
default n
|
||||
|
||||
if RT_USING_SMP
|
||||
rsource "smp/Kconfig"
|
||||
endif
|
||||
|
||||
endmenu
|
||||
70
RT_Thread/examples/utest/testcases/kernel/SConscript
Normal file
70
RT_Thread/examples/utest/testcases/kernel/SConscript
Normal file
@ -0,0 +1,70 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_MEMHEAP_TC']):
|
||||
src += ['memheap_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SMALL_MEM_TC']):
|
||||
src += ['mem_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SLAB_TC']):
|
||||
src += ['slab_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_IRQ_TC']):
|
||||
src += ['irq_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SEMAPHORE_TC']):
|
||||
src += ['semaphore_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_EVENT_TC']):
|
||||
src += ['event_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_TIMER_TC']):
|
||||
src += ['timer_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MESSAGEQUEUE_TC']):
|
||||
src += ['messagequeue_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SIGNAL_TC']):
|
||||
src += ['signal_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MUTEX_TC']):
|
||||
src += ['mutex_tc.c', 'mutex_pi_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MAILBOX_TC']):
|
||||
src += ['mailbox_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_THREAD_TC']):
|
||||
src += ['thread_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_DEVICE_TC']):
|
||||
src += ['device_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_ATOMIC_TC']):
|
||||
src += ['atomic_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_HOOKLIST_TC']):
|
||||
src += ['hooklist_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MTSAFE_KPRINT_TC']):
|
||||
src += ['mtsafe_kprint_tc.c']
|
||||
|
||||
# Stressful testcase for scheduler (MP/UP)
|
||||
if GetDepend(['UTEST_SCHEDULER_TC']):
|
||||
src += ['sched_timed_sem_tc.c']
|
||||
src += ['sched_timed_mtx_tc.c']
|
||||
src += ['sched_mtx_tc.c']
|
||||
src += ['sched_sem_tc.c', 'sched_thread_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
list = os.listdir(cwd)
|
||||
for item in list:
|
||||
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
|
||||
group = group + SConscript(os.path.join(item, 'SConscript'))
|
||||
|
||||
Return('group')
|
||||
173
RT_Thread/examples/utest/testcases/kernel/atomic_tc.c
Normal file
173
RT_Thread/examples/utest/testcases/kernel/atomic_tc.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-07-27 flybreak the first version
|
||||
* 2023-03-21 WangShun add atomic test
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include "rtatomic.h"
|
||||
#include <rthw.h>
|
||||
|
||||
#define THREAD_PRIORITY 25
|
||||
#define THREAD_TIMESLICE 1
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
/* convenience macro - return either 64-bit or 32-bit value */
|
||||
#define ATOMIC_WORD(val_if_64, val_if_32) \
|
||||
((rt_atomic_t)((sizeof(void *) == sizeof(uint64_t)) ? (val_if_64) : (val_if_32)))
|
||||
|
||||
static rt_atomic_t count = 0;
|
||||
static rt_sem_t sem_t;
|
||||
|
||||
static void test_atomic_api(void)
|
||||
{
|
||||
rt_atomic_t base;
|
||||
rt_atomic_t oldval;
|
||||
rt_atomic_t result;
|
||||
|
||||
/* rt_atomic_t */
|
||||
uassert_true(sizeof(rt_atomic_t) == ATOMIC_WORD(sizeof(uint64_t), sizeof(uint32_t)));
|
||||
|
||||
/* rt_atomic_add */
|
||||
base = 0;
|
||||
result = rt_atomic_add(&base, 10);
|
||||
uassert_true(base == 10);
|
||||
uassert_true(result == 0);
|
||||
/* rt_atomic_add negative */
|
||||
base = 2;
|
||||
result = rt_atomic_add(&base, -4);
|
||||
uassert_true(base == -2);
|
||||
uassert_true(result == 2);
|
||||
|
||||
/* rt_atomic_sub */
|
||||
base = 11;
|
||||
result = rt_atomic_sub(&base, 10);
|
||||
uassert_true(base == 1);
|
||||
uassert_true(result == 11);
|
||||
/* rt_atomic_sub negative */
|
||||
base = 2;
|
||||
result = rt_atomic_sub(&base, -5);
|
||||
uassert_true(base == 7);
|
||||
uassert_true(result == 2);
|
||||
|
||||
/* rt_atomic_or */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_or(&base, 0x0F0F);
|
||||
uassert_true(base == 0xFF0F);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_xor */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_xor(&base, 0x0F0F);
|
||||
uassert_true(base == 0xF00F);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_and */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_and(&base, 0x0F0F);
|
||||
uassert_true(base == 0x0F00);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_exchange */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_exchange(&base, 0x0F0F);
|
||||
uassert_true(base == 0x0F0F);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_flag_test_and_set (Flag 0) */
|
||||
base = 0x0;
|
||||
result = rt_atomic_flag_test_and_set(&base);
|
||||
uassert_true(base == 0x1);
|
||||
uassert_true(result == 0x0);
|
||||
/* rt_atomic_flag_test_and_set (Flag 1) */
|
||||
base = 0x1;
|
||||
result = rt_atomic_flag_test_and_set(&base);
|
||||
uassert_true(base == 0x1);
|
||||
uassert_true(result == 0x1);
|
||||
|
||||
/* rt_atomic_flag_clear */
|
||||
base = 0x1;
|
||||
rt_atomic_flag_clear(&base);
|
||||
uassert_true(base == 0x0);
|
||||
|
||||
/* rt_atomic_load */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_load(&base);
|
||||
uassert_true(base == 0xFF00);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_store */
|
||||
base = 0xFF00;
|
||||
rt_atomic_store(&base, 0x0F0F);
|
||||
uassert_true(base == 0x0F0F);
|
||||
|
||||
/* rt_atomic_compare_exchange_strong (equal) */
|
||||
base = 10;
|
||||
oldval = 10;
|
||||
result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
|
||||
uassert_true(base == 11);
|
||||
uassert_true(result == 0x1);
|
||||
/* rt_atomic_compare_exchange_strong (not equal) */
|
||||
base = 10;
|
||||
oldval = 5;
|
||||
result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
|
||||
uassert_true(base == 10);
|
||||
uassert_true(result == 0x0);
|
||||
}
|
||||
|
||||
static void ture_entry(void *parameter)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 1000000; i++)
|
||||
{
|
||||
rt_atomic_add(&count, 1);
|
||||
}
|
||||
rt_sem_release(sem_t);
|
||||
}
|
||||
|
||||
static void test_atomic_add(void)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
size_t i;
|
||||
sem_t = rt_sem_create("atomic_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
|
||||
rt_atomic_store(&count, 0);
|
||||
|
||||
thread = rt_thread_create("t1", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(thread);
|
||||
thread = rt_thread_create("t2", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(thread);
|
||||
thread = rt_thread_create("t3", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(thread);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
rt_sem_take(sem_t, RT_WAITING_FOREVER);
|
||||
}
|
||||
i = rt_atomic_load(&count);
|
||||
uassert_true(i == 3000000);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_atomic_api);
|
||||
UTEST_UNIT_RUN(test_atomic_add);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.atomic_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
59
RT_Thread/examples/utest/testcases/kernel/device_tc.c
Normal file
59
RT_Thread/examples/utest/testcases/kernel/device_tc.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-05-20 Shell the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
static void test_rt_device_find(void)
|
||||
{
|
||||
char _device_name[RT_NAME_MAX + 1] = {0};
|
||||
rt_device_t console;
|
||||
rt_device_t device1, device2, device3;
|
||||
|
||||
console = rt_console_get_device();
|
||||
uassert_not_null(console);
|
||||
rt_memcpy(_device_name, console->parent.name, RT_NAME_MAX);
|
||||
|
||||
/* Test finding a device */
|
||||
device1 = rt_device_find(_device_name);
|
||||
uassert_true(device1 == console);
|
||||
|
||||
/* Test finding another device */
|
||||
device2 = rt_device_find(RT_CONSOLE_DEVICE_NAME);
|
||||
if (rt_strcmp(RT_CONSOLE_DEVICE_NAME, _device_name) == 0)
|
||||
{
|
||||
uassert_true(device2 == device1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_not_null(device2);
|
||||
uassert_true(device2 != device1);
|
||||
}
|
||||
|
||||
/* Test finding a device 3 */
|
||||
device3 = rt_device_find(console->parent.name);
|
||||
uassert_true(device1 == device3);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_rt_device_find);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.device.find", utest_tc_init, utest_tc_cleanup, 5);
|
||||
346
RT_Thread/examples/utest/testcases/kernel/event_tc.c
Normal file
346
RT_Thread/examples/utest/testcases/kernel/event_tc.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-15 liukang the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
#define EVENT_FLAG3 (1 << 3)
|
||||
#define EVENT_FLAG5 (1 << 5)
|
||||
|
||||
static struct rt_event static_event = {0};
|
||||
#ifdef RT_USING_HEAP
|
||||
static rt_event_t dynamic_event = RT_NULL;
|
||||
static rt_uint32_t dynamic_event_recv_thread_finish = 0, dynamic_event_send_thread_finish = 0;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread3_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread3;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread4_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread4;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static rt_uint32_t recv_event_times1 = 0, recv_event_times2 = 0;
|
||||
static rt_uint32_t static_event_recv_thread_finish = 0, static_event_send_thread_finish = 0;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread1_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread1;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread2_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread2;
|
||||
|
||||
#define THREAD_PRIORITY 9
|
||||
#define THREAD_TIMESLICE 5
|
||||
|
||||
static void test_event_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_event_detach(&static_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_event_detach(&static_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_event_detach(void)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_detach(&static_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread1_recv_static_event(void *param)
|
||||
{
|
||||
rt_uint32_t e;
|
||||
|
||||
if (rt_event_recv(&static_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recv_event_times1 = e;
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
if (rt_event_recv(&static_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
recv_event_times2 = e;
|
||||
|
||||
static_event_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread2_send_static_event(void *param)
|
||||
{
|
||||
rt_event_send(&static_event, EVENT_FLAG3);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(&static_event, EVENT_FLAG5);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(&static_event, EVENT_FLAG3);
|
||||
|
||||
static_event_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
|
||||
static void test_static_event_send_recv(void)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
rt_thread_init(&thread1,
|
||||
"thread1",
|
||||
thread1_recv_static_event,
|
||||
RT_NULL,
|
||||
&thread1_stack[0],
|
||||
sizeof(thread1_stack),
|
||||
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread1);
|
||||
|
||||
rt_thread_init(&thread2,
|
||||
"thread2",
|
||||
thread2_send_static_event,
|
||||
RT_NULL,
|
||||
&thread2_stack[0],
|
||||
sizeof(thread2_stack),
|
||||
THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread2);
|
||||
|
||||
while (static_event_recv_thread_finish != 1 || static_event_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (recv_event_times1 == EVENT_FLAG3 && recv_event_times2 == (EVENT_FLAG3 | EVENT_FLAG5))
|
||||
{
|
||||
if (rt_event_detach(&static_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_true(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_event_detach(&static_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static void test_event_create(void)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_FIFO);
|
||||
if (dynamic_event == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_delete(dynamic_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_event_delete(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_FIFO);
|
||||
if (dynamic_event == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_delete(dynamic_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread3_recv_dynamic_event(void *param)
|
||||
{
|
||||
rt_uint32_t e;
|
||||
|
||||
if (rt_event_recv(dynamic_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recv_event_times1 = e;
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
if (rt_event_recv(dynamic_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
recv_event_times2 = e;
|
||||
|
||||
dynamic_event_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread4_send_dynamic_event(void *param)
|
||||
{
|
||||
rt_event_send(dynamic_event, EVENT_FLAG3);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(dynamic_event, EVENT_FLAG5);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(dynamic_event, EVENT_FLAG3);
|
||||
|
||||
dynamic_event_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void test_dynamic_event_send_recv(void)
|
||||
{
|
||||
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_PRIO);
|
||||
if (dynamic_event == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
rt_thread_init(&thread3,
|
||||
"thread3",
|
||||
thread3_recv_dynamic_event,
|
||||
RT_NULL,
|
||||
&thread3_stack[0],
|
||||
sizeof(thread3_stack),
|
||||
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread3);
|
||||
|
||||
rt_thread_init(&thread4,
|
||||
"thread4",
|
||||
thread4_send_dynamic_event,
|
||||
RT_NULL,
|
||||
&thread4_stack[0],
|
||||
sizeof(thread4_stack),
|
||||
THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread4);
|
||||
|
||||
while (dynamic_event_recv_thread_finish != 1 || dynamic_event_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (recv_event_times1 == EVENT_FLAG3 && recv_event_times2 == (EVENT_FLAG3 | EVENT_FLAG5))
|
||||
{
|
||||
if (rt_event_delete(dynamic_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_true(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_event_delete(dynamic_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
static_event_recv_thread_finish = 0;
|
||||
static_event_send_thread_finish = 0;
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_event_recv_thread_finish = 0;
|
||||
dynamic_event_send_thread_finish = 0;
|
||||
#endif
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_event_init);
|
||||
UTEST_UNIT_RUN(test_event_detach);
|
||||
UTEST_UNIT_RUN(test_static_event_send_recv);
|
||||
#ifdef RT_USING_HEAP
|
||||
UTEST_UNIT_RUN(test_event_create);
|
||||
UTEST_UNIT_RUN(test_event_delete);
|
||||
UTEST_UNIT_RUN(test_dynamic_event_send_recv);
|
||||
#endif
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "src.ipc.event_tc", utest_tc_init, utest_tc_cleanup, 60);
|
||||
98
RT_Thread/examples/utest/testcases/kernel/hooklist_tc.c
Normal file
98
RT_Thread/examples/utest/testcases/kernel/hooklist_tc.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-22 Shell Support hook list
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "rtconfig.h"
|
||||
#include "utest.h"
|
||||
#include "utest_assert.h"
|
||||
|
||||
static int hooker1_ent_count;
|
||||
static int hooker2_ent_count;
|
||||
static struct rt_thread thr_tobe_inited;
|
||||
|
||||
static void thread_inited_hooker1(rt_thread_t thread)
|
||||
{
|
||||
LOG_D("%s: count %d", __func__, hooker1_ent_count);
|
||||
hooker1_ent_count += 1;
|
||||
}
|
||||
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_thread_inited, hooker1_node, thread_inited_hooker1);
|
||||
|
||||
static void thread_inited_hooker2(rt_thread_t thread)
|
||||
{
|
||||
LOG_D("%s: count %d", __func__, hooker2_ent_count);
|
||||
hooker2_ent_count += 1;
|
||||
}
|
||||
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_thread_inited, hooker2_node, thread_inited_hooker2);
|
||||
|
||||
static char _thr_stack[UTEST_THR_STACK_SIZE];
|
||||
static void thr_tobe_inited_entry(void *param)
|
||||
{
|
||||
rt_kprintf("Hello!\n");
|
||||
}
|
||||
|
||||
static void hooklist_test(void)
|
||||
{
|
||||
hooker1_ent_count = 0;
|
||||
hooker2_ent_count = 0;
|
||||
rt_thread_inited_sethook(&hooker1_node);
|
||||
rt_thread_inited_sethook(&hooker2_node);
|
||||
|
||||
/* run 1 */
|
||||
rt_thread_init(&thr_tobe_inited,
|
||||
"thr_tobe_inited",
|
||||
thr_tobe_inited_entry,
|
||||
NULL,
|
||||
_thr_stack,
|
||||
sizeof(_thr_stack),
|
||||
25,
|
||||
100);
|
||||
|
||||
uassert_int_equal(hooker1_ent_count, 1);
|
||||
uassert_int_equal(hooker2_ent_count, 1);
|
||||
|
||||
rt_thread_detach(&thr_tobe_inited);
|
||||
rt_thread_mdelay(1); /* wait recycling done */
|
||||
|
||||
/* run 2 */
|
||||
rt_thread_inited_rmhook(&hooker2_node);
|
||||
|
||||
rt_thread_init(&thr_tobe_inited,
|
||||
"thr_tobe_inited",
|
||||
thr_tobe_inited_entry,
|
||||
NULL,
|
||||
_thr_stack,
|
||||
sizeof(_thr_stack),
|
||||
25,
|
||||
100);
|
||||
|
||||
uassert_int_equal(hooker1_ent_count, 2);
|
||||
uassert_int_equal(hooker2_ent_count, 1);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
hooker1_ent_count = 0;
|
||||
hooker2_ent_count = 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_thread_detach(&thr_tobe_inited);
|
||||
rt_thread_inited_rmhook(&hooker1_node);
|
||||
rt_thread_inited_rmhook(&hooker2_node);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(hooklist_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.hooklist_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
78
RT_Thread/examples/utest/testcases/kernel/irq_tc.c
Normal file
78
RT_Thread/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 volatile uint32_t irq_count = 0;
|
||||
static volatile uint32_t max_get_nest_count = 0;
|
||||
|
||||
static void irq_callback()
|
||||
{
|
||||
if(rt_interrupt_get_nest() > max_get_nest_count)
|
||||
{
|
||||
max_get_nest_count = rt_interrupt_get_nest();
|
||||
}
|
||||
irq_count ++;
|
||||
}
|
||||
|
||||
static void irq_test(void)
|
||||
{
|
||||
irq_count = 0;
|
||||
rt_interrupt_enter_sethook(irq_callback);
|
||||
rt_interrupt_leave_sethook(irq_callback);
|
||||
rt_thread_mdelay(2);
|
||||
LOG_D("%s test irq_test! irq_count %d max_get_nest_count %d\n", UTEST_NAME, irq_count, max_get_nest_count);
|
||||
uassert_int_not_equal(0, irq_count);
|
||||
uassert_int_not_equal(0, max_get_nest_count);
|
||||
rt_interrupt_enter_sethook(RT_NULL);
|
||||
rt_interrupt_leave_sethook(RT_NULL);
|
||||
LOG_D("irq_test OK!\n");
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
irq_count = 0;
|
||||
max_get_nest_count = 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void interrupt_test(void)
|
||||
{
|
||||
rt_base_t level;
|
||||
uint32_t i = 1000;
|
||||
|
||||
rt_interrupt_enter_sethook(irq_callback);
|
||||
rt_interrupt_leave_sethook(irq_callback);
|
||||
irq_count = 0;
|
||||
level = rt_hw_interrupt_disable();
|
||||
while(i)
|
||||
{
|
||||
i --;
|
||||
}
|
||||
uassert_int_equal(0, irq_count);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_interrupt_enter_sethook(RT_NULL);
|
||||
rt_interrupt_leave_sethook(RT_NULL);
|
||||
|
||||
}
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(irq_test);
|
||||
UTEST_UNIT_RUN(interrupt_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.irq_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
374
RT_Thread/examples/utest/testcases/kernel/mailbox_tc.c
Normal file
374
RT_Thread/examples/utest/testcases/kernel/mailbox_tc.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-08 liukang the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
static struct rt_mailbox test_static_mb;
|
||||
static char mb_pool[128];
|
||||
|
||||
static rt_mailbox_t test_dynamic_mb;
|
||||
|
||||
static uint8_t static_mb_recv_thread_finish, static_mb_send_thread_finish;
|
||||
static uint8_t dynamic_mb_recv_thread_finish, dynamic_mb_send_thread_finish;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread1_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread1;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread2_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread2;
|
||||
|
||||
#define THREAD_PRIORITY 9
|
||||
#define THREAD_TIMESLICE 5
|
||||
|
||||
static rt_thread_t mb_send = RT_NULL;
|
||||
static rt_thread_t mb_recv = RT_NULL;
|
||||
|
||||
static rt_uint8_t mb_send_str1[] = "this is first mail!";
|
||||
static rt_uint8_t mb_send_str2[] = "this is second mail!";
|
||||
static rt_uint8_t mb_send_str3[] = "this is thirdy mail!";
|
||||
|
||||
static rt_uint8_t *mb_recv_str1;
|
||||
static rt_uint8_t *mb_recv_str2;
|
||||
static rt_uint8_t *mb_recv_str3;
|
||||
|
||||
static void test_mailbox_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_mailbox_deatch(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_mailbox_create(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_mailbox_delete(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread2_send_static_mb(void *arg)
|
||||
{
|
||||
rt_err_t res = RT_EOK;
|
||||
|
||||
res = rt_mb_send(&test_static_mb, (rt_ubase_t)&mb_send_str1);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_send_wait(&test_static_mb, (rt_ubase_t)&mb_send_str2, 10);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_urgent(&test_static_mb, (rt_ubase_t)&mb_send_str3);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
static_mb_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread1_recv_static_mb(void *arg)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str1, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str1, (const char *)mb_send_str1) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str2, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str2, (const char *)mb_send_str2) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str3, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str3, (const char *)mb_send_str3) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
static_mb_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void test_static_mailbox_send_recv(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
rt_thread_init(&thread1,
|
||||
"thread1",
|
||||
thread1_recv_static_mb,
|
||||
RT_NULL,
|
||||
&thread1_stack[0],
|
||||
sizeof(thread1_stack),
|
||||
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread1);
|
||||
|
||||
rt_thread_init(&thread2,
|
||||
"thread2",
|
||||
thread2_send_static_mb,
|
||||
RT_NULL,
|
||||
&thread2_stack[0],
|
||||
sizeof(thread2_stack),
|
||||
THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread2);
|
||||
|
||||
while (static_mb_recv_thread_finish != 1 || static_mb_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (rt_mb_detach(&test_static_mb) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread4_send_dynamic_mb(void *arg)
|
||||
{
|
||||
rt_err_t res = RT_EOK;
|
||||
|
||||
res = rt_mb_send(test_dynamic_mb, (rt_ubase_t)&mb_send_str1);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_send_wait(test_dynamic_mb, (rt_ubase_t)&mb_send_str2, 10);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_urgent(test_dynamic_mb, (rt_ubase_t)&mb_send_str3);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
dynamic_mb_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread3_recv_dynamic_mb(void *arg)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str1, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str1, (const char *)mb_send_str1) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str2, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str2, (const char *)mb_send_str2) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str3, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str3, (const char *)mb_send_str3) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
dynamic_mb_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void test_dynamic_mailbox_send_recv(void)
|
||||
{
|
||||
test_dynamic_mb = rt_mb_create("mbt", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
mb_recv = rt_thread_create("mb_recv_thread",
|
||||
thread3_recv_dynamic_mb,
|
||||
RT_NULL,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
THREAD_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (mb_recv == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_startup(mb_recv);
|
||||
|
||||
mb_send = rt_thread_create("mb_send_thread",
|
||||
thread4_send_dynamic_mb,
|
||||
RT_NULL,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
THREAD_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (mb_send == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_startup(mb_send);
|
||||
|
||||
while (dynamic_mb_recv_thread_finish != 1 || dynamic_mb_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (rt_mb_delete(test_dynamic_mb) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_mailbox_init);
|
||||
UTEST_UNIT_RUN(test_mailbox_deatch);
|
||||
UTEST_UNIT_RUN(test_mailbox_create);
|
||||
UTEST_UNIT_RUN(test_mailbox_delete);
|
||||
UTEST_UNIT_RUN(test_static_mailbox_send_recv);
|
||||
UTEST_UNIT_RUN(test_dynamic_mailbox_send_recv);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "src.ipc.mailbox_tc", utest_tc_init, utest_tc_cleanup, 60);
|
||||
585
RT_Thread/examples/utest/testcases/kernel/mem_tc.c
Normal file
585
RT_Thread/examples/utest/testcases/kernel/mem_tc.c
Normal file
@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-14 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
struct rt_small_mem_item
|
||||
{
|
||||
rt_ubase_t pool_ptr; /**< small memory object addr */
|
||||
rt_size_t next; /**< next free item */
|
||||
rt_size_t prev; /**< prev free item */
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
rt_uint8_t thread[8]; /**< thread name */
|
||||
#else
|
||||
rt_uint8_t thread[4]; /**< thread name */
|
||||
#endif /* ARCH_CPU_64BIT */
|
||||
#endif /* RT_USING_MEMTRACE */
|
||||
};
|
||||
|
||||
struct rt_small_mem
|
||||
{
|
||||
struct rt_memory parent; /**< inherit from rt_memory */
|
||||
rt_uint8_t *heap_ptr; /**< pointer to the heap */
|
||||
struct rt_small_mem_item *heap_end;
|
||||
struct rt_small_mem_item *lfree;
|
||||
rt_size_t mem_size_aligned; /**< aligned memory size */
|
||||
};
|
||||
|
||||
#define MEM_SIZE(_heap, _mem) \
|
||||
(((struct rt_small_mem_item *)(_mem))->next - ((rt_ubase_t)(_mem) - \
|
||||
(rt_ubase_t)((_heap)->heap_ptr)) - RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE))
|
||||
|
||||
#define TEST_MEM_SIZE 1024
|
||||
|
||||
static rt_size_t max_block(struct rt_small_mem *heap)
|
||||
{
|
||||
struct rt_small_mem_item *mem;
|
||||
rt_size_t max = 0, size;
|
||||
|
||||
for (mem = (struct rt_small_mem_item *)heap->heap_ptr;
|
||||
mem != heap->heap_end;
|
||||
mem = (struct rt_small_mem_item *)&heap->heap_ptr[mem->next])
|
||||
{
|
||||
if (((rt_ubase_t)mem->pool_ptr & 0x1) == 0)
|
||||
{
|
||||
size = MEM_SIZE(heap, mem);
|
||||
if (size > max)
|
||||
{
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
{
|
||||
if (*(rt_uint8_t *)ptr != v)
|
||||
return *(rt_uint8_t *)ptr - v;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mem_test_context
|
||||
{
|
||||
void *ptr;
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
static void mem_functional_test(void)
|
||||
{
|
||||
rt_size_t total_size;
|
||||
rt_uint8_t *buf;
|
||||
struct rt_small_mem *heap;
|
||||
rt_uint8_t magic = __LINE__;
|
||||
|
||||
/* Prepare test memory */
|
||||
buf = rt_malloc(TEST_MEM_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
|
||||
/* small heap init */
|
||||
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
|
||||
/* get total size */
|
||||
total_size = max_block(heap);
|
||||
uassert_int_not_equal(total_size, 0);
|
||||
/*
|
||||
* Allocate all memory at a time and test whether
|
||||
* the memory allocation release function is effective
|
||||
*/
|
||||
{
|
||||
struct mem_test_context ctx;
|
||||
ctx.magic = magic++;
|
||||
ctx.size = max_block(heap);
|
||||
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
|
||||
uassert_not_null(ctx.ptr);
|
||||
rt_memset(ctx.ptr, ctx.magic, ctx.size);
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
rt_smem_free(ctx.ptr);
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/*
|
||||
* Apply for memory release sequentially and
|
||||
* test whether memory block merging is effective
|
||||
*/
|
||||
{
|
||||
rt_size_t i, max_free = 0;
|
||||
struct mem_test_context ctx[3];
|
||||
/* alloc mem */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
ctx[i].magic = magic++;
|
||||
ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
|
||||
ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
|
||||
uassert_not_null(ctx[i].ptr);
|
||||
rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
|
||||
}
|
||||
/* All memory has been applied. The remaining memory should be 0 */
|
||||
uassert_int_equal(max_block(heap), 0);
|
||||
/* Verify that the memory data is correct */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
}
|
||||
/* Sequential memory release */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
rt_smem_free(ctx[i].ptr);
|
||||
max_free += ctx[i].size;
|
||||
uassert_true(max_block(heap) >= max_free);
|
||||
}
|
||||
/* Check whether the memory is fully merged */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/*
|
||||
* Apply for memory release at an interval to
|
||||
* test whether memory block merging is effective
|
||||
*/
|
||||
{
|
||||
rt_size_t i, max_free = 0;
|
||||
struct mem_test_context ctx[3];
|
||||
/* alloc mem */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
ctx[i].magic = magic++;
|
||||
ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
|
||||
ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
|
||||
uassert_not_null(ctx[i].ptr);
|
||||
rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
|
||||
}
|
||||
/* All memory has been applied. The remaining memory should be 0 */
|
||||
uassert_int_equal(max_block(heap), 0);
|
||||
/* Verify that the memory data is correct */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
}
|
||||
/* Release even address */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
rt_smem_free(ctx[i].ptr);
|
||||
uassert_true(max_block(heap) >= ctx[0].size);
|
||||
}
|
||||
}
|
||||
/* Release odd addresses and merge memory blocks */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
rt_smem_free(ctx[i].ptr);
|
||||
max_free += ctx[i - 1].size + ctx[i + 1].size;
|
||||
uassert_true(max_block(heap) >= max_free);
|
||||
}
|
||||
}
|
||||
/* Check whether the memory is fully merged */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* mem realloc test,Small - > Large */
|
||||
{
|
||||
/* Request a piece of memory for subsequent reallocation operations */
|
||||
struct mem_test_context ctx[3];
|
||||
ctx[0].magic = magic++;
|
||||
ctx[0].size = max_block(heap) / 3;
|
||||
ctx[0].ptr = rt_smem_alloc(&heap->parent, ctx[0].size);
|
||||
uassert_not_null(ctx[0].ptr);
|
||||
rt_memset(ctx[0].ptr, ctx[0].magic, ctx[0].size);
|
||||
/* Apply for a small piece of memory and split the continuous memory */
|
||||
ctx[1].magic = magic++;
|
||||
ctx[1].size = RT_ALIGN_SIZE;
|
||||
ctx[1].ptr = rt_smem_alloc(&heap->parent, ctx[1].size);
|
||||
uassert_not_null(ctx[1].ptr);
|
||||
rt_memset(ctx[1].ptr, ctx[1].magic, ctx[1].size);
|
||||
/* Check whether the maximum memory block is larger than the first piece of memory */
|
||||
uassert_true(max_block(heap) > ctx[0].size);
|
||||
/* Reallocate the first piece of memory */
|
||||
ctx[2].magic = magic++;
|
||||
ctx[2].size = max_block(heap);
|
||||
ctx[2].ptr = rt_smem_realloc(&heap->parent, ctx[0].ptr, ctx[2].size);
|
||||
uassert_not_null(ctx[2].ptr);
|
||||
uassert_int_not_equal(ctx[0].ptr, ctx[2].ptr);
|
||||
uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[0].magic, ctx[0].size), 0);
|
||||
rt_memset(ctx[2].ptr, ctx[2].magic, ctx[2].size);
|
||||
/* Free the second piece of memory */
|
||||
uassert_int_equal(_mem_cmp(ctx[1].ptr, ctx[1].magic, ctx[1].size), 0);
|
||||
rt_smem_free(ctx[1].ptr);
|
||||
/* Free reallocated memory */
|
||||
uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[2].magic, ctx[2].size), 0);
|
||||
rt_smem_free(ctx[2].ptr);
|
||||
/* Check memory integrity */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* mem realloc test,Large - > Small */
|
||||
{
|
||||
rt_size_t max_free;
|
||||
struct mem_test_context ctx;
|
||||
/* alloc a piece of memory */
|
||||
ctx.magic = magic++;
|
||||
ctx.size = max_block(heap) / 2;
|
||||
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
|
||||
uassert_not_null(ctx.ptr);
|
||||
rt_memset(ctx.ptr, ctx.magic, ctx.size);
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
/* Get remaining memory */
|
||||
max_free = max_block(heap);
|
||||
/* Change memory size */
|
||||
ctx.size = ctx.size / 2;
|
||||
uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
|
||||
/* Get remaining size */
|
||||
uassert_true(max_block(heap) > max_free);
|
||||
/* Free memory */
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
rt_smem_free(ctx.ptr);
|
||||
/* Check memory integrity */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* mem realloc test,equal */
|
||||
{
|
||||
rt_size_t max_free;
|
||||
struct mem_test_context ctx;
|
||||
/* alloc a piece of memory */
|
||||
ctx.magic = magic++;
|
||||
ctx.size = max_block(heap) / 2;
|
||||
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
|
||||
uassert_not_null(ctx.ptr);
|
||||
rt_memset(ctx.ptr, ctx.magic, ctx.size);
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
/* Get remaining memory */
|
||||
max_free = max_block(heap);
|
||||
/* Do not change memory size */
|
||||
uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
|
||||
/* Get remaining size */
|
||||
uassert_true(max_block(heap) == max_free);
|
||||
/* Free memory */
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
rt_smem_free(ctx.ptr);
|
||||
/* Check memory integrity */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* small heap deinit */
|
||||
rt_smem_detach(&heap->parent);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
struct mem_alloc_context
|
||||
{
|
||||
rt_list_t node;
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
struct mem_alloc_head
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_size_t count;
|
||||
rt_tick_t start;
|
||||
rt_tick_t end;
|
||||
rt_tick_t interval;
|
||||
};
|
||||
|
||||
#define MEM_RANG_ALLOC_BLK_MIN 2
|
||||
#define MEM_RANG_ALLOC_BLK_MAX 5
|
||||
#define MEM_RANG_ALLOC_TEST_TIME 5
|
||||
|
||||
static void mem_alloc_test(void)
|
||||
{
|
||||
struct mem_alloc_head head;
|
||||
rt_uint8_t *buf;
|
||||
struct rt_small_mem *heap;
|
||||
rt_size_t total_size, size;
|
||||
struct mem_alloc_context *ctx;
|
||||
|
||||
/* init */
|
||||
rt_list_init(&head.list);
|
||||
head.count = 0;
|
||||
head.start = rt_tick_get();
|
||||
head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
|
||||
head.interval = (head.end - head.start) / 20;
|
||||
buf = rt_malloc(TEST_MEM_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
|
||||
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
|
||||
total_size = max_block(heap);
|
||||
uassert_int_not_equal(total_size, 0);
|
||||
/* test run */
|
||||
while (head.end - head.start < RT_TICK_MAX / 2)
|
||||
{
|
||||
if (rt_tick_get() - head.start >= head.interval)
|
||||
{
|
||||
head.start = rt_tick_get();
|
||||
rt_kprintf("#");
|
||||
}
|
||||
/* %60 probability to perform alloc operation */
|
||||
if (rand() % 10 >= 4)
|
||||
{
|
||||
size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
|
||||
size *= sizeof(struct mem_alloc_context);
|
||||
ctx = rt_smem_alloc(&heap->parent, size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
if (head.count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
size = head.count / 2;
|
||||
while (size != head.count)
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_free(ctx);
|
||||
head.count --;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx)
|
||||
{
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx);
|
||||
}
|
||||
rt_memset(ctx, 0, size);
|
||||
rt_list_init(&ctx->node);
|
||||
ctx->size = size;
|
||||
ctx->magic = rand() & 0xff;
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
rt_list_insert_after(&head.list, &ctx->node);
|
||||
head.count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rt_list_isempty(&head.list))
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_free(ctx);
|
||||
head.count --;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!rt_list_isempty(&head.list))
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_free(ctx);
|
||||
head.count --;
|
||||
}
|
||||
uassert_int_equal(head.count, 0);
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
/* small heap deinit */
|
||||
rt_smem_detach(&heap->parent);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
#define MEM_RANG_REALLOC_BLK_MIN 0
|
||||
#define MEM_RANG_REALLOC_BLK_MAX 5
|
||||
#define MEM_RANG_REALLOC_TEST_TIME 5
|
||||
|
||||
struct mem_realloc_context
|
||||
{
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
struct mem_realloc_head
|
||||
{
|
||||
struct mem_realloc_context **ctx_tab;
|
||||
rt_size_t count;
|
||||
rt_tick_t start;
|
||||
rt_tick_t end;
|
||||
rt_tick_t interval;
|
||||
};
|
||||
|
||||
static void mem_realloc_test(void)
|
||||
{
|
||||
struct mem_realloc_head head;
|
||||
rt_uint8_t *buf;
|
||||
struct rt_small_mem *heap;
|
||||
rt_size_t total_size, size, idx;
|
||||
struct mem_realloc_context *ctx;
|
||||
int res;
|
||||
|
||||
size = RT_ALIGN(sizeof(struct mem_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
|
||||
size = TEST_MEM_SIZE / size;
|
||||
/* init */
|
||||
head.ctx_tab = RT_NULL;
|
||||
head.count = size;
|
||||
head.start = rt_tick_get();
|
||||
head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
|
||||
head.interval = (head.end - head.start) / 20;
|
||||
buf = rt_malloc(TEST_MEM_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
|
||||
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
|
||||
total_size = max_block(heap);
|
||||
uassert_int_not_equal(total_size, 0);
|
||||
/* init ctx tab */
|
||||
size = head.count * sizeof(struct mem_realloc_context *);
|
||||
head.ctx_tab = rt_smem_alloc(&heap->parent, size);
|
||||
uassert_not_null(head.ctx_tab);
|
||||
rt_memset(head.ctx_tab, 0, size);
|
||||
/* test run */
|
||||
while (head.end - head.start < RT_TICK_MAX / 2)
|
||||
{
|
||||
if (rt_tick_get() - head.start >= head.interval)
|
||||
{
|
||||
head.start = rt_tick_get();
|
||||
rt_kprintf("#");
|
||||
}
|
||||
size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
|
||||
size *= sizeof(struct mem_realloc_context);
|
||||
idx = rand() % head.count;
|
||||
ctx = rt_smem_realloc(&heap->parent, head.ctx_tab[idx], size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
if (head.ctx_tab[idx])
|
||||
{
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (idx = 0; idx < head.count; idx++)
|
||||
{
|
||||
ctx = head.ctx_tab[idx];
|
||||
if (rand() % 2 && ctx)
|
||||
{
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_realloc(&heap->parent, ctx, 0);
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* check mem */
|
||||
if (head.ctx_tab[idx] != RT_NULL)
|
||||
{
|
||||
res = 0;
|
||||
if (ctx->size < size)
|
||||
{
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
/* init mem */
|
||||
ctx->magic = rand() & 0xff;
|
||||
ctx->size = size;
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
head.ctx_tab[idx] = ctx;
|
||||
}
|
||||
/* free all mem */
|
||||
for (idx = 0; idx < head.count; idx++)
|
||||
{
|
||||
ctx = head.ctx_tab[idx];
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_realloc(&heap->parent, ctx, 0);
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
uassert_int_not_equal(max_block(heap), total_size);
|
||||
/* small heap deinit */
|
||||
rt_smem_detach(&heap->parent);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(mem_functional_test);
|
||||
UTEST_UNIT_RUN(mem_alloc_test);
|
||||
UTEST_UNIT_RUN(mem_realloc_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.mem_tc", utest_tc_init, utest_tc_cleanup, 20);
|
||||
97
RT_Thread/examples/utest/testcases/kernel/memheap_tc.c
Normal file
97
RT_Thread/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);
|
||||
234
RT_Thread/examples/utest/testcases/kernel/messagequeue_tc.c
Normal file
234
RT_Thread/examples/utest/testcases/kernel/messagequeue_tc.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-28 Sherman the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
* fix in smp
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
#define MSG_SIZE 4
|
||||
#define MAX_MSGS 5
|
||||
|
||||
static struct rt_messagequeue static_mq;
|
||||
static rt_uint8_t mq_buf[RT_MQ_BUF_SIZE(MSG_SIZE, MAX_MSGS)];
|
||||
|
||||
static struct rt_thread mq_send_thread;
|
||||
static struct rt_thread mq_recv_thread;
|
||||
static rt_uint8_t mq_send_stack[UTEST_THR_STACK_SIZE];
|
||||
static rt_uint8_t mq_recv_stack[UTEST_THR_STACK_SIZE];
|
||||
|
||||
static struct rt_event finish_e;
|
||||
#define MQSEND_FINISH 0x01
|
||||
#define MQRECV_FINIHS 0x02
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static rt_mq_t dynamic_mq;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static void test_mq_init(void)
|
||||
{
|
||||
rt_err_t ret;
|
||||
ret = rt_mq_init(&static_mq,"testmq1", mq_buf, MSG_SIZE, sizeof(mq_buf), RT_IPC_FLAG_FIFO);
|
||||
uassert_true(ret == RT_EOK);
|
||||
}
|
||||
|
||||
static void test_mq_create(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_mq = rt_mq_create("testmq2", MSG_SIZE, MAX_MSGS, RT_IPC_FLAG_FIFO);
|
||||
uassert_true(dynamic_mq != RT_NULL);
|
||||
#endif /* RT_USING_HEAP */
|
||||
}
|
||||
|
||||
static void mq_send_case(rt_mq_t testmq)
|
||||
{
|
||||
rt_uint32_t send_buf[MAX_MSGS+1] = {0};
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
for (int var = 0; var < MAX_MSGS; ++var)
|
||||
{
|
||||
send_buf[var] = var + 1;
|
||||
ret = rt_mq_send_wait(testmq, &send_buf[var], sizeof(send_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
}
|
||||
send_buf[MAX_MSGS] = MAX_MSGS + 1;
|
||||
ret = rt_mq_send(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]));
|
||||
uassert_true(ret == -RT_EFULL);
|
||||
|
||||
ret = rt_mq_send_wait(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
while (testmq->entry != 0)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
|
||||
ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
ret = rt_mq_send(testmq, &send_buf[2], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
ret = rt_mq_urgent(testmq, &send_buf[0], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
while (testmq->entry != 0)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_MESSAGEQUEUE_PRIORITY
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[3], sizeof(send_buf[0]), 3, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[0], sizeof(send_buf[0]), 0, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[2], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[4], sizeof(send_buf[0]), 4, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[1], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
while (testmq->entry != 0)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_control(testmq, RT_IPC_CMD_RESET, RT_NULL);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(testmq->entry == 0);
|
||||
}
|
||||
|
||||
static void mq_send_entry(void *param)
|
||||
{
|
||||
mq_send_case(&static_mq);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
if(dynamic_mq != RT_NULL)
|
||||
{
|
||||
mq_send_case(dynamic_mq);
|
||||
}
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
rt_event_send(&finish_e, MQSEND_FINISH);
|
||||
}
|
||||
|
||||
static void mq_recv_case(rt_mq_t testmq)
|
||||
{
|
||||
rt_uint32_t recv_buf[MAX_MSGS+1] = {0};
|
||||
rt_ssize_t ret = RT_EOK;
|
||||
|
||||
for (int var = 0; var < MAX_MSGS + 1; ++var)
|
||||
{
|
||||
ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret >= 0);
|
||||
uassert_true(recv_buf[var] == (var + 1));
|
||||
}
|
||||
|
||||
for (int var = 0; var < 3; ++var)
|
||||
{
|
||||
ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret >= 0);
|
||||
uassert_true(recv_buf[var] == (var + 1));
|
||||
}
|
||||
#ifdef RT_USING_MESSAGEQUEUE_PRIORITY
|
||||
rt_int32_t msg_prio;
|
||||
while (testmq->entry == MAX_MSGS)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
for (int var = 0; var < MAX_MSGS; ++var)
|
||||
{
|
||||
ret = rt_mq_recv_prio(testmq, &recv_buf[var], sizeof(recv_buf[0]), &msg_prio, RT_WAITING_FOREVER, RT_UNINTERRUPTIBLE);
|
||||
rt_kprintf("msg_prio = %d\r\n", msg_prio);
|
||||
uassert_true(ret >= 0);
|
||||
uassert_true(recv_buf[var] == (MAX_MSGS - var));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mq_recv_entry(void *param)
|
||||
{
|
||||
mq_recv_case(&static_mq);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
if(dynamic_mq != RT_NULL)
|
||||
{
|
||||
mq_recv_case(dynamic_mq);
|
||||
}
|
||||
#endif /* RT_USING_HEAP */
|
||||
rt_event_send(&finish_e, MQRECV_FINIHS);
|
||||
}
|
||||
|
||||
static void test_mq_testcase(void)
|
||||
{
|
||||
rt_thread_startup(&mq_send_thread);
|
||||
rt_thread_startup(&mq_recv_thread);
|
||||
|
||||
rt_event_recv(&finish_e, MQSEND_FINISH | MQRECV_FINIHS, RT_EVENT_FLAG_AND, RT_WAITING_FOREVER, RT_NULL);
|
||||
}
|
||||
|
||||
static void test_mq_detach(void)
|
||||
{
|
||||
rt_err_t ret = rt_mq_detach(&static_mq);
|
||||
uassert_true(ret == RT_EOK);
|
||||
}
|
||||
|
||||
static void test_mq_delete(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t ret = rt_mq_delete(dynamic_mq);
|
||||
uassert_true(ret == RT_EOK);
|
||||
#endif /* RT_USING_HEAP */
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_err_t ret ;
|
||||
ret = rt_thread_init(&mq_send_thread, "mq_send", mq_send_entry, RT_NULL, mq_send_stack, sizeof(mq_send_stack), 22, 20);
|
||||
if(ret != RT_EOK)
|
||||
return -RT_ERROR;
|
||||
|
||||
ret = rt_thread_init(&mq_recv_thread, "mq_recv", mq_recv_entry, RT_NULL, mq_recv_stack, sizeof(mq_recv_stack), 23, 20);
|
||||
if(ret != RT_EOK)
|
||||
return -RT_ERROR;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
rt_thread_control(&mq_send_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
rt_thread_control(&mq_recv_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
#endif
|
||||
|
||||
ret = rt_event_init(&finish_e, "finish", RT_IPC_FLAG_FIFO);
|
||||
if(ret != RT_EOK)
|
||||
return -RT_ERROR;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_mq_init);
|
||||
UTEST_UNIT_RUN(test_mq_create);
|
||||
UTEST_UNIT_RUN(test_mq_testcase);
|
||||
UTEST_UNIT_RUN(test_mq_detach);
|
||||
UTEST_UNIT_RUN(test_mq_delete);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.messagequeue_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
68
RT_Thread/examples/utest/testcases/kernel/mtsafe_kprint_tc.c
Normal file
68
RT_Thread/examples/utest/testcases/kernel/mtsafe_kprint_tc.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-25 Shell the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_LOOP_TIMES 20
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
|
||||
static void _thread_entry(void *param)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
rt_kprintf("This is thread %p\n", rt_thread_self());
|
||||
rt_thread_mdelay(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
#define TEST_THREAD_COUNT 16
|
||||
|
||||
static void mtsafe_kprint_tc(void)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_thread_t new_thread =
|
||||
rt_thread_create(
|
||||
"test",
|
||||
_thread_entry,
|
||||
NULL,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY,
|
||||
100);
|
||||
rt_thread_startup(new_thread);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(mtsafe_kprint_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.mtsafe_kprint", utest_tc_init, utest_tc_cleanup, 10);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user