Files
kunlun/cli/host_interface/plc/iot_cli_host_rate_test.c
2024-09-28 14:24:04 +08:00

626 lines
21 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "os_utils_api.h"
#include "iot_io.h"
#include "iot_cli_host_interface.h"
#include "iot_cli_plc_module.h"
#include "iot_cli_rate_test.h"
#include "iot_cli_msg.h"
#include "iot_cli_plc_tx_rx.h"
#if IOT_CLI_RATE_TEST_EN
iot_plc_host_rate_test_t *rate_test_info = NULL;
extern iot_plc_host_config_t *host_config;
extern iot_cli_host_info_t *host_info;
extern iot_cli_t cli;
/* timer for rate test timer */
static void iot_cli_rate_test_timer(timer_id_t timer_id, void *arg)
{
(void)timer_id;
(void)arg;
iot_task_msg_t *msg;
msg = iot_cli_create_cli_msg(IOT_CLI_RATE_TEST_TIMER, NULL);
if (msg) {
iot_task_queue_msg(cli.cli_task_h, msg, IOT_CLI_QUEUE_TIMER);
}
}
#if PLC_SUPPORT_CCO_ROLE
static void iot_cli_rate_test_send_start_param()
{
cli_host_rate_test_param param;
param.downlink = rate_test_info->downlink;
param.msdu_size = rate_test_info->msdu_size;
param.send_rate = rate_test_info->send_rate;
param.test_duration = rate_test_info->test_duration;
param.test_id = rate_test_info->test_id;
iot_printf("send rate test start to sta, downlink %d, msdu size %d,"
" rate %d, duration %d\n", param.downlink, param.msdu_size,
param.send_rate, param.test_duration);
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_START, rate_test_info->dst,
(uint8_t*)&param, sizeof(cli_host_rate_test_param));
}
#endif
static void cli_send_rate_test_packet()
{
iot_pkt_t *test_pkt = NULL;
uint32_t data_len = IOT_PLC_RATE_TEST_HEADER_SIZE;
IOT_ASSERT(rate_test_info);
if (rate_test_info->msdu_size > data_len) {
data_len = rate_test_info->msdu_size - data_len;
} else {
data_len = rate_test_info->msdu_size;
}
if (data_len < sizeof(cli_host_test_rate_packet)) {
data_len = sizeof(cli_host_test_rate_packet);
}
test_pkt = iot_cli_create_pkt_plc(IOT_PLC_MSG_TYPE_UNICAST,
IOT_PLC_LOCAL_RETRY_CNT, CLI_MODULEID_HOSTINTERFACE,
CLI_MSGID_RATE_TEST, NULL, rate_test_info->dst, rate_test_info->dst,
data_len);
if (test_pkt != NULL) {
uint8_t *ptr = iot_pkt_block_ptr(test_pkt, IOT_PKT_BLOCK_TAIL);
cli_host_test_rate_packet * rate_test_pkt =
(cli_host_test_rate_packet *)ptr;
if (rate_test_pkt) {
rate_test_pkt->packet_idx = rate_test_info->send_packet_idx;
rate_test_pkt->test_id = rate_test_info->test_id;
rate_test_pkt->test_duration = rate_test_info->test_duration;
}
iot_printf("send rate test packet, idx %d, test id %d\n",
rate_test_pkt->packet_idx, rate_test_pkt->test_id);
for (uint32_t i = sizeof(cli_host_test_rate_packet); i < data_len; i++)
{
ptr[i] = (uint8_t)os_rand();
}
iot_pkt_put(test_pkt, data_len);
iot_plc_send_msdu(host_config->app_handle, test_pkt);
rate_test_info->send_packet_idx++;
}
}
static void cli_send_rate_test_result(
uint8_t downlink, uint8_t *mac, uint8_t *dest_mac)
{
cli_host_test_rate_result result;
result.test_id = rate_test_info->test_id;
result.downlink = downlink;
result.recv_pkts = rate_test_info->recv_packets;
iot_mac_addr_cpy(result.dst, mac);
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_TEST_RESP, dest_mac,
(uint8_t*)&result, sizeof(cli_host_test_rate_result));
}
/* rate test timer handler */
void iot_cli_rate_test_handle_timer_msg()
{
switch (rate_test_info->rate_test_state)
{
case IOT_PLC_RATE_TEST_SENDER:
rate_test_info->ticks_count++;
// sta stop sending timer when no reply for more than 5s
if ((IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) &&
(!rate_test_info->test_duration)) {
if (0 ==
(rate_test_info->ticks_count % IOT_PLC_RATE_TEST_MAX_TICKS)) {
if (rate_test_info->rate_test_result) {
rate_test_info->rate_test_result = 0;
} else {
iot_printf("sta stop sending rate "
"test packets since no reply\n");
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
}
rate_test_info->ticks_count = 0;
}
}
for (uint16_t i = 0; i < rate_test_info->pakcets_per_second; i++) {
cli_send_rate_test_packet();
}
// stop test when duration hit
if (rate_test_info->test_duration) {
if (0 == (rate_test_info->ticks_count %
(rate_test_info->test_duration / IOT_PLC_RATE_TEST_INTERVAL))) {
iot_printf("stop sending rate test packet"
" since duration expired\n");
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
}
}
break;
case IOT_PLC_RATE_TEST_RECVER:
#if PLC_SUPPORT_CCO_ROLE
if (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) {
if (!rate_test_info->recv_packets) {
rate_test_info->ticks_count++;
if (0 ==
(rate_test_info->ticks_count %
IOT_PLC_RATE_TEST_MAX_TICKS)) {
//send start cmd to sta
iot_cli_rate_test_send_start_param();
rate_test_info->ticks_count = 0;
}
} else if(rate_test_info->test_duration) {
rate_test_info->ticks_count = 0;
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_IN_TEST;
}
}
#endif
break;
case IOT_PLC_RATE_TEST_IN_TEST:
rate_test_info->ticks_count++;
if (rate_test_info->ticks_count >
(rate_test_info->test_duration / IOT_PLC_RATE_TEST_INTERVAL)) {
if (0 == (rate_test_info->ticks_count %
(rate_test_info->test_duration /
(IOT_PLC_RATE_TEST_INTERVAL * 5)))) {
iot_printf("send rate test result in completed state\n");
if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) {
cli_send_rate_test_result(
1, host_config->mac_addr, host_config->cco_mac);
}
#if PLC_SUPPORT_CCO_ROLE
else {
cli_send_rate_test_result(
0, rate_test_info->dst, rate_test_info->dst);
}
#endif
}
// report at most 10 times then terminate
if (rate_test_info->ticks_count ==
(rate_test_info->test_duration /
IOT_PLC_RATE_TEST_INTERVAL * 3)) {
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
}
}
break;
case IOT_PLC_RATE_TEST_STOP:
#if PLC_SUPPORT_CCO_ROLE
if (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) {
rate_test_info->ticks_count++;
if (0 ==
(rate_test_info->ticks_count % IOT_PLC_RATE_TEST_STOP_TICKS)) {
cli_host_rate_test_stop stop;
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_STOP, rate_test_info->dst,
(uint8_t*)&stop, sizeof(cli_host_rate_test_stop));
}
}
#endif
break;
default:
break;
}
}
void cli_recv_rate_test_packet(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
cli_host_test_rate_packet * rate_test_pkt = NULL;
rate_test_pkt = (cli_host_test_rate_packet *)buffer;
IOT_ASSERT(rate_test_pkt);
IOT_ASSERT(bufferlen >= sizeof(*rate_test_pkt));
if ((rate_test_pkt->test_id == rate_test_info->test_id) &&
((IOT_PLC_RATE_TEST_STOP == rate_test_info->rate_test_state) ||
((IOT_PLC_RATE_TEST_IN_TEST == rate_test_info->rate_test_state) &&
(rate_test_info->ticks_count > rate_test_info->test_duration /
IOT_PLC_RATE_TEST_INTERVAL)))) {
iot_printf("rate test drop packet\n");
return;
}
if (rate_test_info->test_id != rate_test_pkt->test_id) {
iot_printf("drop old test %d, start new %d\n",
rate_test_info->test_id, rate_test_pkt->test_id);
rate_test_info->test_id = rate_test_pkt->test_id;
rate_test_info->recv_packets = 0;
}
rate_test_info->recv_packets++;
iot_printf("recv rate test packet, idx %d, test id %d, recv packets %d\n",
rate_test_pkt->packet_idx, rate_test_pkt->test_id,
rate_test_info->recv_packets);
if (!rate_test_pkt->test_duration) {
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_RECVER;
rate_test_info->test_duration = rate_test_pkt->test_duration;
#if PLC_SUPPORT_CCO_ROLE
if (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) {
// for no duration test, stop cco timer for start sta
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
}
#endif
} else if (rate_test_info->recv_packets == 1) {
rate_test_info->ticks_count = 0;
rate_test_info->test_duration = rate_test_pkt->test_duration;
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_IN_TEST;
if (!os_is_timer_active(rate_test_info->rate_test_timer)) {
os_start_timer(rate_test_info->rate_test_timer,
IOT_PLC_RATE_TEST_INTERVAL);
}
}
//for no duration, report rate test result per 10 recved packets
if ((!rate_test_info->test_duration) &&
(0 ==
(rate_test_info->recv_packets % IOT_PLC_RATE_TEST_RESULT_TICKS))) {
if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) {
//send test result to cco
iot_printf("sta send downlink rate test result , recv rate %d\n",
rate_test_info->recv_packets);
cli_send_rate_test_result(
1, host_config->mac_addr, host_config->cco_mac);
}
#if PLC_SUPPORT_CCO_ROLE
else {
iot_printf("coo send uplink rate test result, recv rate %d\n",
rate_test_info->recv_packets);
cli_send_rate_test_result(
0, rate_test_info->dst, rate_test_info->dst);
}
#endif
}
}
void cli_recv_rate_test_result(
uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
cli_host_test_rate_result *result = NULL;
result = (cli_host_test_rate_result *)buffer;
IOT_ASSERT(result);
IOT_ASSERT(bufferlen >= sizeof(*result));
iot_printf("recv rate test result, test id %d\n", result->test_id);
//if plcmgr connect a 3rd STA
if ((!(iot_mac_addr_valid(rate_test_info->launch_mac)) &&
(!iot_mac_addr_valid(rate_test_info->dst)))){
iot_cli_send_to_host(CLI_MSGID_RATE_TEST_RESP,
(uint8_t*)result, sizeof(cli_host_test_rate_result), NULL);
return;
}
if (IOT_PLC_RATE_TEST_STOP == rate_test_info->rate_test_state) {
iot_printf("rate test stop\n");
return;
}
if (result->test_id != rate_test_info->test_id) {
iot_printf("drop test id not match result current id %d, "
"result id %d\n", rate_test_info->test_id, result->test_id);
return;
}
if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) {
rate_test_info->rate_test_result = 1;
result->downlink = 0;
iot_printf("sta recv uplink rate test result , result->recv_pkts %d,"
" rate_test_info->send_packet_idx %d\n",
result->recv_pkts, rate_test_info->send_packet_idx);
result->recv_pkts =
result->recv_pkts * 100 / (rate_test_info->send_packet_idx + 1);
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_TEST_RESP, rate_test_info->launch_mac,
(uint8_t*)result, sizeof(cli_host_test_rate_result));
}
#if PLC_SUPPORT_CCO_ROLE
else {
if (result->downlink) {
if ((IOT_PLC_RATE_TEST_RECVER ==
rate_test_info->rate_test_state) ||
(IOT_PLC_RATE_TEST_IN_TEST ==
rate_test_info->rate_test_state)) {
iot_printf("drop test result since new test started\n");
return;
}
iot_printf("cco recv downlink rate test result"
" , result->recv_pkts %d, rate_test_info->send_packet_idx %d\n",
result->recv_pkts, rate_test_info->send_packet_idx);
result->downlink = 1;
result->recv_pkts =
result->recv_pkts * 100 / (rate_test_info->send_packet_idx + 1);
} else {
iot_printf("cco forward uplink rate test result"
" , test id %d, recv rate %d\n",
result->test_id, result->recv_pkts);
}
iot_cli_send_to_host(CLI_MSGID_RATE_TEST_RESP,
(uint8_t*)result,
sizeof(cli_host_test_rate_result),
rate_test_info->launch_mac);
}
#endif
}
void cli_rate_test_start(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
cli_host_rate_test_param *param = NULL;
param = (cli_host_rate_test_param *)buffer;
IOT_ASSERT(param);
IOT_ASSERT(bufferlen >= sizeof(*param));
IOT_ASSERT(rate_test_info);
if (rate_test_info->send_packet_idx) {
iot_printf("rate test started, drop new test\n");
}
rate_test_info->downlink = param->downlink;
rate_test_info->msdu_size = param->msdu_size;
rate_test_info->send_rate = param->send_rate;
rate_test_info->test_duration = param->test_duration;
if (src_mac)
os_mem_cpy(rate_test_info->launch_mac, src_mac, \
sizeof(rate_test_info->launch_mac));
else
os_mem_set(rate_test_info->launch_mac, 0, \
sizeof(rate_test_info->launch_mac));
if (rate_test_info->test_duration &&
(rate_test_info->test_duration < IOT_PLC_RATE_TEST_DEFAULT_DURATION)) {
rate_test_info->test_duration = IOT_PLC_RATE_TEST_DEFAULT_DURATION;
}
rate_test_info->recv_packets = 0;
rate_test_info->ticks_count = 0;
rate_test_info->rate_test_result = 0;
rate_test_info->send_packet_idx = 0;
if (!rate_test_info->msdu_size) {
rate_test_info->msdu_size = IOT_PLC_RATE_TEST_DEFAULT_MSDU_SIZE;
}
rate_test_info->pakcets_per_second =
rate_test_info->send_rate /
rate_test_info->msdu_size / IOT_PLC_RATE_TEST_TICKS_SECOND;
if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) {
iot_mac_addr_cpy(rate_test_info->dst, host_config->cco_mac);
} else {
iot_mac_addr_cpy(rate_test_info->dst, param->dst);
}
if (IOT_PLC_DEV_ROLE_CCO == host_config->dev_role) {
//cco send stop ack to plc mgr
cli_host_rate_test_param_ack start_ack;
iot_cli_send_to_host(CLI_MSGID_RATE_START_ACK,
(uint8_t*)&start_ack,
sizeof(cli_host_rate_test_param_ack), src_mac);
}
if (rate_test_info->downlink) {
// create new test id
rate_test_info->test_id++;
iot_printf("sta start uplink rate test start, test id %d\n",
rate_test_info->test_id);
// set state to sender and send rate test packet in timer
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_SENDER;
} else if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) {
// create new test id
rate_test_info->test_id = param->test_id;
// set state to sender and send rate test packet in timer
iot_printf("sta start upink rate test start, test id %d\n",
rate_test_info->test_id);
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_SENDER;
}
#if PLC_SUPPORT_CCO_ROLE
else {
rate_test_info->test_id++;
iot_printf("cco forward rate test start to sta, test id %d\n",
rate_test_info->test_id);
param->test_id = rate_test_info->test_id;
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_START, param->dst,
(uint8_t*)param, sizeof(cli_host_rate_test_param));
//set state to recver and start sta in timer
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_RECVER;
}
#endif
//start timer for rate test
if (!os_is_timer_active(rate_test_info->rate_test_timer)) {
os_start_timer(rate_test_info->rate_test_timer,
IOT_PLC_RATE_TEST_INTERVAL);
}
}
void cli_rate_test_stop(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)src_mac;
cli_host_rate_test_stop *stop = NULL;
stop = (cli_host_rate_test_stop *)buffer;
IOT_ASSERT(stop);
IOT_ASSERT(bufferlen >= sizeof(*stop));
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_STOP;
if (IOT_PLC_DEV_ROLE_CCO != host_config->dev_role) {
cli_host_rate_test_stop_ack stop_ack;
// sta stop send rate test timer
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
//sta send stop ack to cco
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_STOP_ACK, host_config->cco_mac,
(uint8_t*)&stop_ack, sizeof(cli_host_rate_test_stop_ack));
}
#if PLC_SUPPORT_CCO_ROLE
else {
//cco send stop ack to plc mgr
cli_host_rate_test_stop_ack stop_ack;
iot_cli_send_to_host(CLI_MSGID_RATE_STOP_ACK,
(uint8_t*)&stop_ack, sizeof(cli_host_rate_test_stop_ack), \
rate_test_info->launch_mac);
if (rate_test_info->downlink) {
// cco stop send rate test timer
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
} else {
//cco forward stop cmd to sta
iot_cli_host_send_data_plc(IOT_PLC_MSG_TYPE_UNICAST,
CLI_MSGID_RATE_STOP, rate_test_info->dst,
(uint8_t*)stop, sizeof(cli_host_rate_test_stop));
if (!os_is_timer_active(rate_test_info->rate_test_timer)) {
os_start_timer(rate_test_info->rate_test_timer,
IOT_PLC_RATE_TEST_INTERVAL);
}
}
}
#endif
}
void cli_rate_test_stop_ack(uint8_t *buffer, uint32_t bufferlen)
{
(void)buffer;
(void)bufferlen;
// cco stop stop rate test timer
if (os_is_timer_active(rate_test_info->rate_test_timer)) {
os_stop_timer(rate_test_info->rate_test_timer);
}
}
void iot_cli_rate_test_init()
{
rate_test_info = (iot_plc_host_rate_test_t *)os_mem_malloc(IOT_CLI_MID,
sizeof(iot_plc_host_rate_test_t));
if (rate_test_info) {
rate_test_info->rate_test_timer = os_create_timer(IOT_CLI_MID, 1,
iot_cli_rate_test_timer, NULL);
rate_test_info->send_packet_idx = 0;
rate_test_info->recv_packets = 0;
rate_test_info->test_id = 0;
} else {
iot_printf("rate test info alloc failed\n");
}
}
void iot_cli_rate_test_deinit()
{
if (rate_test_info) {
if (rate_test_info->rate_test_timer) {
os_delete_timer(rate_test_info->rate_test_timer);
rate_test_info->rate_test_timer = 0;
rate_test_info->rate_test_state = IOT_PLC_RATE_TEST_INIT;
}
os_mem_free(rate_test_info);
rate_test_info = NULL;
}
}
#else /* IOT_CLI_RATE_TEST_EN */
void cli_recv_rate_test_packet(uint8_t *buffer, uint32_t bufferlen,
uint8_t *src_mac)
{
(void)buffer;
(void)bufferlen;
(void)src_mac;
}
void cli_recv_rate_test_result(uint8_t *buffer, uint32_t bufferlen,
uint8_t *src_mac)
{
(void)buffer;
(void)bufferlen;
(void)src_mac;
}
void cli_rate_test_start(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)buffer;
(void)bufferlen;
(void)src_mac;
}
void cli_rate_test_stop(uint8_t *buffer, uint32_t bufferlen, uint8_t *src_mac)
{
(void)buffer;
(void)bufferlen;
(void)src_mac;
}
void cli_rate_test_stop_ack(uint8_t *buffer, uint32_t bufferlen)
{
(void)buffer;
(void)bufferlen;
}
void iot_cli_rate_test_handle_timer_msg()
{
}
void iot_cli_rate_test_init()
{
}
void iot_cli_rate_test_deinit()
{
}
#endif /* IOT_CLI_RATE_TEST_EN */