215 lines
5.4 KiB
C
215 lines
5.4 KiB
C
/**
|
|
* @file
|
|
* @brief test of BACnet/SC event interface
|
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
|
* @author Kirill Neznamov <kirill.neznamov@dsr-corporation.com>
|
|
* @author Mikhail Antropov <michail.antropov@dsr-corporation.com>
|
|
* @author Ondřej Hruška <ondra@ondrovo.com>
|
|
* @author Patrick Grimm <patrick@lunatiki.de>
|
|
* @date 2020
|
|
* @copyright SPDX-License-Identifier: MIT
|
|
*/
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <zephyr/ztest.h>
|
|
#include <bacnet/datalink/bsc/bsc-event.h>
|
|
|
|
typedef enum {
|
|
STAGE_NONE,
|
|
STAGE_WAIT_1,
|
|
STAGE_WAIT_2,
|
|
STAGE_TIMEDWAIT_TIMEOUT,
|
|
STAGE_TIMEDWAIT_OK,
|
|
} TEST_STAGE;
|
|
static TEST_STAGE test_stage = STAGE_NONE;
|
|
|
|
#define TIMEOUT_CHILD 400
|
|
#define TIMEOUT_MIN 200
|
|
#define TIMEOUT_MAX 600
|
|
#define TIMEOUT_SLEEP 2
|
|
#define WAITTIME_MIN (TIMEOUT_SLEEP * 1000 - 100)
|
|
#define WAITTIME_MAX (TIMEOUT_SLEEP * 1000 + 100)
|
|
#define MULTIPLE_WAIT_THREADS_NUM 50
|
|
|
|
DWORD WINAPI child_func(LPVOID lpParam)
|
|
{
|
|
BSC_EVENT *event = (BSC_EVENT *)lpParam;
|
|
zassert_not_null(event, NULL);
|
|
|
|
while (test_stage != STAGE_WAIT_1) {
|
|
Sleep(1);
|
|
}
|
|
bsc_event_signal(event);
|
|
|
|
while (test_stage != STAGE_WAIT_2) {
|
|
Sleep(1);
|
|
}
|
|
bsc_event_signal(event);
|
|
|
|
while (test_stage != STAGE_TIMEDWAIT_TIMEOUT) {
|
|
Sleep(1);
|
|
}
|
|
Sleep(TIMEOUT_CHILD);
|
|
bsc_event_signal(event);
|
|
|
|
while (test_stage != STAGE_TIMEDWAIT_OK) {
|
|
Sleep(1);
|
|
}
|
|
|
|
Sleep(TIMEOUT_CHILD);
|
|
bsc_event_signal(event);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void test_bsc_event1(void)
|
|
{
|
|
BSC_EVENT *event;
|
|
HANDLE thread;
|
|
DWORD threadID;
|
|
bool b;
|
|
ULONGLONG time1;
|
|
ULONGLONG time2;
|
|
ULONGLONG timediff;
|
|
|
|
test_stage = STAGE_NONE;
|
|
event = bsc_event_init();
|
|
zassert_not_null(event, NULL);
|
|
|
|
// run child and wait when child running
|
|
thread = CreateThread(
|
|
NULL, // default security attributes
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE)child_func, event,
|
|
0, // default creation flags
|
|
&threadID); // receive thread identifier
|
|
zassert_not_null(thread, NULL);
|
|
|
|
test_stage = STAGE_WAIT_1;
|
|
bsc_event_wait(event);
|
|
|
|
test_stage = STAGE_WAIT_2;
|
|
bsc_event_wait(event);
|
|
|
|
test_stage = STAGE_TIMEDWAIT_TIMEOUT;
|
|
b = bsc_event_timedwait(event, TIMEOUT_MIN);
|
|
zassert_false(b, NULL);
|
|
|
|
test_stage = STAGE_TIMEDWAIT_OK;
|
|
b = bsc_event_timedwait(event, TIMEOUT_MAX);
|
|
zassert_true(b, NULL);
|
|
|
|
time1 = GetTickCount64();
|
|
bsc_wait(TIMEOUT_SLEEP);
|
|
time2 = GetTickCount64();
|
|
timediff = time2 - time1;
|
|
zassert_true(timediff >= TIMEOUT_SLEEP * 1000, NULL);
|
|
|
|
WaitForSingleObject(thread, INFINITE);
|
|
CloseHandle(thread);
|
|
bsc_event_deinit(event);
|
|
}
|
|
|
|
DWORD WINAPI thread_func(LPVOID lpParam)
|
|
{
|
|
BSC_EVENT *event = (BSC_EVENT *)lpParam;
|
|
zassert_not_null(event, NULL);
|
|
bsc_event_wait(event);
|
|
return 0;
|
|
}
|
|
|
|
static void test_bsc_event2(void)
|
|
{
|
|
int i;
|
|
BSC_EVENT *event;
|
|
DWORD tid[MULTIPLE_WAIT_THREADS_NUM];
|
|
HANDLE thread[MULTIPLE_WAIT_THREADS_NUM];
|
|
|
|
event = bsc_event_init();
|
|
zassert_not_null(event, NULL);
|
|
|
|
for (i = 0; i < MULTIPLE_WAIT_THREADS_NUM; i++) {
|
|
thread[i] = CreateThread(
|
|
NULL, // default security attributes
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE)thread_func, event,
|
|
0, // default creation flags
|
|
&tid[i]); // receive thread identifier
|
|
zassert_not_null(thread[i], NULL);
|
|
}
|
|
|
|
bsc_wait(1);
|
|
bsc_event_signal(event);
|
|
|
|
for (i = 0; i < MULTIPLE_WAIT_THREADS_NUM; i++) {
|
|
WaitForSingleObject(thread[i], INFINITE);
|
|
CloseHandle(thread[i]);
|
|
}
|
|
|
|
bsc_event_deinit(event);
|
|
}
|
|
|
|
typedef struct {
|
|
BSC_EVENT *event;
|
|
BOOL result;
|
|
} test_param_t;
|
|
|
|
DWORD WINAPI thread_func2(LPVOID lpParam)
|
|
{
|
|
test_param_t *p = (test_param_t *)lpParam;
|
|
zassert_not_null(p->event, NULL);
|
|
// use some big timeout value, 24 hours seems to be enough
|
|
p->result = bsc_event_timedwait(p->event, 24 * 60 * 60 * 1000);
|
|
return 0;
|
|
}
|
|
|
|
static void test_bsc_event3(void)
|
|
{
|
|
int i;
|
|
BSC_EVENT *event;
|
|
DWORD tid[MULTIPLE_WAIT_THREADS_NUM];
|
|
HANDLE thread[MULTIPLE_WAIT_THREADS_NUM];
|
|
test_param_t results[MULTIPLE_WAIT_THREADS_NUM];
|
|
|
|
event = bsc_event_init();
|
|
zassert_not_null(event, NULL);
|
|
|
|
for (i = 0; i < MULTIPLE_WAIT_THREADS_NUM; i++) {
|
|
results[i].event = event;
|
|
results[i].result = FALSE;
|
|
thread[i] = CreateThread(
|
|
NULL, // default security attributes
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE)thread_func2, &results[i],
|
|
0, // default creation flags
|
|
&tid[i]); // receive thread identifier
|
|
zassert_not_null(thread[i], NULL);
|
|
}
|
|
|
|
bsc_wait(1);
|
|
bsc_event_signal(event);
|
|
|
|
for (i = 0; i < MULTIPLE_WAIT_THREADS_NUM; i++) {
|
|
WaitForSingleObject(thread[i], INFINITE);
|
|
CloseHandle(thread[i]);
|
|
}
|
|
|
|
for (i = 0; i < MULTIPLE_WAIT_THREADS_NUM; i++) {
|
|
zassert_equal(results[i].result == true, true, NULL);
|
|
}
|
|
|
|
bsc_event_deinit(event);
|
|
}
|
|
|
|
void test_main(void)
|
|
{
|
|
ztest_test_suite(bsc_event_test1, ztest_unit_test(test_bsc_event1));
|
|
ztest_test_suite(bsc_event_test2, ztest_unit_test(test_bsc_event2));
|
|
ztest_test_suite(bsc_event_test3, ztest_unit_test(test_bsc_event3));
|
|
ztest_run_test_suite(bsc_event_test1);
|
|
ztest_run_test_suite(bsc_event_test2);
|
|
ztest_run_test_suite(bsc_event_test3);
|
|
}
|